diff options
104 files changed, 2817 insertions, 1818 deletions
diff --git a/android/Android.bp b/android/Android.bp index 773aa6ae1..a32e8f253 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -67,6 +67,7 @@ bootstrap_go_package { "rule_builder.go", "sandbox.go", "sdk.go", + "sdk_version.go", "singleton.go", "singleton_module.go", "soong_config_modules.go", diff --git a/android/apex.go b/android/apex.go index 257bdad03..7f9f0f5c3 100644 --- a/android/apex.go +++ b/android/apex.go @@ -803,60 +803,73 @@ var minSdkVersionAllowlist = func(apiMap map[string]int) map[string]ApiLevel { } return list }(map[string]int{ - "adbd": 30, - "android.net.ipsec.ike": 30, - "apache-commons-compress": 29, - "bouncycastle_ike_digests": 30, - "brotli-java": 29, - "captiveportal-lib": 28, - "flatbuffer_headers": 30, - "framework-permission": 30, - "gemmlowp_headers": 30, - "ike-internals": 30, - "kotlinx-coroutines-android": 28, - "kotlinx-coroutines-core": 28, - "libadb_crypto": 30, - "libadb_pairing_auth": 30, - "libadb_pairing_connection": 30, - "libadb_pairing_server": 30, - "libadb_protos": 30, - "libadb_tls_connection": 30, - "libadbconnection_client": 30, - "libadbconnection_server": 30, - "libadbd_core": 30, - "libadbd_services": 30, - "libadbd": 30, - "libapp_processes_protos_lite": 30, - "libasyncio": 30, - "libbrotli": 30, - "libbuildversion": 30, - "libcrypto_static": 30, - "libcrypto_utils": 30, - "libdiagnose_usb": 30, - "libeigen": 30, - "liblz4": 30, - "libmdnssd": 30, - "libneuralnetworks_common": 30, - "libneuralnetworks_headers": 30, - "libneuralnetworks": 30, - "libprocpartition": 30, - "libprotobuf-java-lite": 30, - "libprotoutil": 30, - "libqemu_pipe": 30, - "libsync": 30, - "libtextclassifier_hash_headers": 30, - "libtextclassifier_hash_static": 30, - "libtflite_kernel_utils": 30, - "libwatchdog": 29, - "libzstd": 30, - "metrics-constants-protos": 28, - "net-utils-framework-common": 29, - "permissioncontroller-statsd": 28, - "philox_random_headers": 30, - "philox_random": 30, - "service-permission": 30, - "tensorflow_headers": 30, - "xz-java": 29, + "adbd": 30, + "android.net.ipsec.ike": 30, + "androidx.annotation_annotation-nodeps": 29, + "androidx.arch.core_core-common-nodeps": 29, + "androidx.collection_collection-nodeps": 29, + "androidx.collection_collection-ktx-nodeps": 30, + "androidx.concurrent_concurrent-futures-nodeps": 30, + "androidx.lifecycle_lifecycle-common-java8-nodeps": 30, + "androidx.lifecycle_lifecycle-common-nodeps": 29, + "androidx.room_room-common-nodeps": 30, + "androidx-constraintlayout_constraintlayout-solver-nodeps": 29, + "apache-commons-compress": 29, + "bouncycastle_ike_digests": 30, + "brotli-java": 29, + "captiveportal-lib": 28, + "error_prone_annotations": 30, + "flatbuffer_headers": 30, + "framework-permission": 30, + "gemmlowp_headers": 30, + "guava-listenablefuture-prebuilt-jar": 30, + "ike-internals": 30, + "kotlinx-coroutines-android": 28, + "kotlinx-coroutines-android-nodeps": 30, + "kotlinx-coroutines-core": 28, + "kotlinx-coroutines-core-nodeps": 30, + "libadb_crypto": 30, + "libadb_pairing_auth": 30, + "libadb_pairing_connection": 30, + "libadb_pairing_server": 30, + "libadb_protos": 30, + "libadb_tls_connection": 30, + "libadbconnection_client": 30, + "libadbconnection_server": 30, + "libadbd_core": 30, + "libadbd_services": 30, + "libadbd": 30, + "libapp_processes_protos_lite": 30, + "libasyncio": 30, + "libbrotli": 30, + "libbuildversion": 30, + "libcrypto_static": 30, + "libcrypto_utils": 30, + "libdiagnose_usb": 30, + "libeigen": 30, + "liblz4": 30, + "libmdnssd": 30, + "libneuralnetworks_common": 30, + "libneuralnetworks_headers": 30, + "libneuralnetworks": 30, + "libprocpartition": 30, + "libprotobuf-java-lite": 30, + "libprotoutil": 30, + "libqemu_pipe": 30, + "libsync": 30, + "libtextclassifier_hash_headers": 30, + "libtextclassifier_hash_static": 30, + "libtflite_kernel_utils": 30, + "libwatchdog": 29, + "libzstd": 30, + "metrics-constants-protos": 28, + "net-utils-framework-common": 29, + "permissioncontroller-statsd": 28, + "philox_random_headers": 30, + "philox_random": 30, + "service-permission": 30, + "tensorflow_headers": 30, + "xz-java": 29, }) // Function called while walking an APEX's payload dependencies. diff --git a/android/api_levels.go b/android/api_levels.go index 2f6a9d29d..9bc7e837b 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -31,9 +31,9 @@ const previewAPILevelBase = 9000 // ApiLevelFromUser or ApiLevelOrPanic. // // The different *types* of API levels are handled separately. Currently only -// Java has these, and they're managed with the sdkKind enum of the sdkSpec. A -// future cleanup should be to migrate sdkSpec to using ApiLevel instead of its -// sdkVersion int, and to move sdkSpec into this package. +// Java has these, and they're managed with the SdkKind enum of the SdkSpec. A +// future cleanup should be to migrate SdkSpec to using ApiLevel instead of its +// SdkVersion int, and to move SdkSpec into this package. type ApiLevel struct { // The string representation of the API level. value string diff --git a/android/arch.go b/android/arch.go index 20b4ab07d..3eff5d5e0 100644 --- a/android/arch.go +++ b/android/arch.go @@ -1709,3 +1709,90 @@ func (m *ModuleBase) GetArchProperties(dst interface{}) map[ArchType]interface{} } return archToProp } + +// GetTargetProperties returns a map of OS target (e.g. android, windows) to the +// values of the properties of the 'dst' struct that are specific to that OS +// target. +// +// For example, passing a struct { Foo bool, Bar string } will return an +// interface{} that can be type asserted back into the same struct, containing +// the os-specific property value specified by the module if defined. +// +// While this looks similar to GetArchProperties, the internal representation of +// the properties have a slightly different layout to warrant a standalone +// lookup function. +func (m *ModuleBase) GetTargetProperties(dst interface{}) map[OsType]interface{} { + // Return value of the arch types to the prop values for that arch. + osToProp := map[OsType]interface{}{} + + // Nothing to do for non-OS/arch-specific modules. + if !m.ArchSpecific() { + return osToProp + } + + // archProperties has the type of [][]interface{}. Looks complicated, so + // let's explain this step by step. + // + // Loop over the outer index, which determines the property struct that + // contains a matching set of properties in dst that we're interested in. + // For example, BaseCompilerProperties or BaseLinkerProperties. + for i := range m.archProperties { + if m.archProperties[i] == nil { + continue + } + + // Iterate over the supported OS types + for _, os := range OsTypeList { + // e.g android, linux_bionic + field := os.Field + + // If it's not nil, loop over the inner index, which determines the arch variant + // of the prop type. In an Android.bp file, this is like looping over: + // + // target: { android: { key: value, ... }, linux_bionic: { key: value, ... } } + for _, archProperties := range m.archProperties[i] { + archPropValues := reflect.ValueOf(archProperties).Elem() + + // This is the archPropRoot struct. Traverse into the Targetnested struct. + src := archPropValues.FieldByName("Target").Elem() + + // Step into non-nil pointers to structs in the src value. + if src.Kind() == reflect.Ptr { + if src.IsNil() { + continue + } + src = src.Elem() + } + + // Find the requested field (e.g. android, linux_bionic) in the src struct. + src = src.FieldByName(field) + + // Validation steps. We want valid non-nil pointers to structs. + if !src.IsValid() || src.IsNil() { + continue + } + + if src.Kind() != reflect.Ptr || src.Elem().Kind() != reflect.Struct { + continue + } + + // Clone the destination prop, since we want a unique prop struct per arch. + dstClone := reflect.New(reflect.ValueOf(dst).Elem().Type()).Interface() + + // Copy the located property struct into the cloned destination property struct. + err := proptools.ExtendMatchingProperties([]interface{}{dstClone}, src.Interface(), nil, proptools.OrderReplace) + if err != nil { + // This is fine, it just means the src struct doesn't match. + continue + } + + // Found the prop for the os, you have. + osToProp[os] = dstClone + + // Go to the next prop. + break + } + } + } + return osToProp +} diff --git a/android/bazel.go b/android/bazel.go index 5bb3879e4..2587328a9 100644 --- a/android/bazel.go +++ b/android/bazel.go @@ -108,6 +108,11 @@ type Bp2BuildConfig map[string]BazelConversionConfigEntry type BazelConversionConfigEntry int const ( + // A sentinel value to be used as a key in Bp2BuildConfig for modules with + // no package path. This is also the module dir for top level Android.bp + // modules. + BP2BUILD_TOPLEVEL = "." + // iota + 1 ensures that the int value is not 0 when used in the Bp2buildAllowlist map, // which can also mean that the key doesn't exist in a lookup. @@ -129,49 +134,61 @@ var ( } // Per-module denylist to always opt modules out. - bp2buildModuleDoNotConvert = map[string]bool{ - "libBionicBenchmarksUtils": true, - "libbionic_spawn_benchmark": true, - "libc_jemalloc_wrapper": true, - "libc_bootstrap": true, - "libc_init_static": true, - "libc_init_dynamic": true, - "libc_tzcode": true, - "libc_freebsd": true, - "libc_freebsd_large_stack": true, - "libc_netbsd": true, - "libc_openbsd_ndk": true, - "libc_openbsd_large_stack": true, - "libc_openbsd": true, - "libc_gdtoa": true, - "libc_fortify": true, - "libc_bionic": true, - "libc_bionic_ndk": true, - "libc_bionic_systrace": true, - "libc_pthread": true, - "libc_syscalls": true, - "libc_aeabi": true, - "libc_ndk": true, - "libc_nopthread": true, - "libc_common": true, - "libc_static_dispatch": true, - "libc_dynamic_dispatch": true, - "libc_common_static": true, - "libc_common_shared": true, - "libc_unwind_static": true, - "libc_nomalloc": true, - "libasync_safe": true, - "libc_malloc_debug_backtrace": true, - "libsystemproperties": true, - "libdl_static": true, - "liblinker_main": true, - "liblinker_malloc": true, - "liblinker_debuggerd_stub": true, - "libbionic_tests_headers_posix": true, - "libc_dns": true, + bp2buildModuleDoNotConvertList = []string{ + "libBionicBenchmarksUtils", // ruperts@, cc_library_static + "libbionic_spawn_benchmark", // ruperts@, cc_library_static, depends on //system/libbase + "libc_jemalloc_wrapper", // ruperts@, cc_library_static, depends on //external/jemalloc_new + "libc_bootstrap", // ruperts@, cc_library_static + "libc_init_static", // ruperts@, cc_library_static + "libc_init_dynamic", // ruperts@, cc_library_static + "libc_tzcode", // ruperts@, cc_library_static + "libc_freebsd", // ruperts@, cc_library_static + "libc_freebsd_large_stack", // ruperts@, cc_library_static + "libc_netbsd", // ruperts@, cc_library_static + "libc_openbsd_ndk", // ruperts@, cc_library_static + "libc_openbsd_large_stack", // ruperts@, cc_library_static + "libc_openbsd", // ruperts@, cc_library_static + "libc_gdtoa", // ruperts@, cc_library_static + "libc_fortify", // ruperts@, cc_library_static + "libc_bionic", // ruperts@, cc_library_static + "libc_bionic_ndk", // ruperts@, cc_library_static, depends on //bionic/libc/system_properties + "libc_bionic_systrace", // ruperts@, cc_library_static + "libc_pthread", // ruperts@, cc_library_static + "libc_syscalls", // ruperts@, cc_library_static + "libc_aeabi", // ruperts@, cc_library_static + "libc_ndk", // ruperts@, cc_library_static, depends on //bionic/libm:libm + "libc_nopthread", // ruperts@, cc_library_static, depends on //external/arm-optimized-routines + "libc_common", // ruperts@, cc_library_static, depends on //bionic/libc:libc_nopthread + "libc_static_dispatch", // ruperts@, cc_library_static + "libc_dynamic_dispatch", // ruperts@, cc_library_static + "libc_common_static", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common + "libc_common_shared", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common + "libc_unwind_static", // ruperts@, cc_library_static + "libc_nomalloc", // ruperts@, cc_library_static, depends on //bionic/libc:libc_common + "libasync_safe", // ruperts@, cc_library_static + "libc_malloc_debug_backtrace", // ruperts@, cc_library_static, depends on //system/libbase + "libsystemproperties", // ruperts@, cc_library_static, depends on //system/core/property_service/libpropertyinfoparser + "libdl_static", // ruperts@, cc_library_static + "liblinker_main", // ruperts@, cc_library_static, depends on //system/libbase + "liblinker_malloc", // ruperts@, cc_library_static, depends on //system/logging/liblog:liblog + "liblinker_debuggerd_stub", // ruperts@, cc_library_static, depends on //system/libbase + "libbionic_tests_headers_posix", // ruperts@, cc_library_static + "libc_dns", // ruperts@, cc_library_static + "generated_android_ids", // cparsons@, genrule + "note_memtag_heap_async", // cparsons@, cc_library_static + "note_memtag_heap_sync", // cparsons@, cc_library_static } + + // Used for quicker lookups + bp2buildModuleDoNotConvert = map[string]bool{} ) +func init() { + for _, moduleName := range bp2buildModuleDoNotConvertList { + bp2buildModuleDoNotConvert[moduleName] = true + } +} + // ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build. func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bool { if bp2buildModuleDoNotConvert[ctx.Module().Name()] { @@ -212,10 +229,15 @@ func (b *BazelModuleBase) ConvertWithBp2build(ctx BazelConversionPathContext) bo func bp2buildDefaultTrueRecursively(packagePath string, config Bp2BuildConfig) bool { ret := false + // Return exact matches in the config. + if config[packagePath] == Bp2BuildDefaultTrueRecursively { + return true + } if config[packagePath] == Bp2BuildDefaultFalse { return false } + // If not, check for the config recursively. packagePrefix := "" // e.g. for x/y/z, iterate over x, x/y, then x/y/z, taking the final value from the allowlist. for _, part := range strings.Split(packagePath, "/") { diff --git a/android/bazel_handler.go b/android/bazel_handler.go index 0595d68a1..04b70d6b3 100644 --- a/android/bazel_handler.go +++ b/android/bazel_handler.go @@ -27,6 +27,7 @@ import ( "sync" "android/soong/bazel/cquery" + "github.com/google/blueprint/bootstrap" "android/soong/bazel" @@ -37,7 +38,6 @@ type CqueryRequestType int const ( getAllFiles CqueryRequestType = iota - getCcObjectFiles getAllFilesAndCcObjectFiles ) @@ -56,10 +56,6 @@ type BazelContext interface { // Returns result files built by building the given bazel target label. GetOutputFiles(label string, archType ArchType) ([]string, bool) - // Returns object files produced by compiling the given cc-related target. - // Retrieves these files from Bazel's CcInfo provider. - GetCcObjectFiles(label string, archType ArchType) ([]string, bool) - // TODO(cparsons): Other cquery-related methods should be added here. // Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order). GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) @@ -116,11 +112,6 @@ func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]str return result, ok } -func (m MockBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]string, bool) { - result, ok := m.AllFiles[label] - return result, ok -} - func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { result, ok := m.AllFiles[label] return result, result, ok @@ -154,16 +145,6 @@ func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([ return ret, ok } -func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) ([]string, bool) { - rawString, ok := bazelCtx.cquery(label, cquery.GetCcObjectFiles, archType) - var returnResult []string - if ok { - bazelOutput := strings.TrimSpace(rawString) - returnResult = cquery.GetCcObjectFiles.ParseResult(bazelOutput).([]string) - } - return returnResult, ok -} - func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { var outputFiles []string var ccObjects []string @@ -183,10 +164,6 @@ func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]str panic("unimplemented") } -func (n noopBazelContext) GetCcObjectFiles(label string, archType ArchType) ([]string, bool) { - panic("unimplemented") -} - func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) { panic("unimplemented") } @@ -293,13 +270,23 @@ func (context *bazelContext) issueBazelCommand(runName bazel.RunName, command st cmdFlags = append(cmdFlags, labels...) cmdFlags = append(cmdFlags, "--package_path=%workspace%/"+context.intermediatesDir()) cmdFlags = append(cmdFlags, "--profile="+shared.BazelMetricsFilename(context, runName)) - // Set default platforms to canonicalized values for mixed builds requests. If these are set - // in the bazelrc, they will have values that are non-canonicalized, and thus be invalid. - // The actual platform values here may be overridden by configuration transitions from the buildroot. + + // Set default platforms to canonicalized values for mixed builds requests. + // If these are set in the bazelrc, they will have values that are + // non-canonicalized to @sourceroot labels, and thus be invalid when + // referenced from the buildroot. + // + // The actual platform values here may be overridden by configuration + // transitions from the buildroot. cmdFlags = append(cmdFlags, - fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:generic_x86_64"))) + fmt.Sprintf("--platforms=%s", canonicalizeLabel("//build/bazel/platforms:android_x86_64"))) cmdFlags = append(cmdFlags, fmt.Sprintf("--extra_toolchains=%s", canonicalizeLabel("//prebuilts/clang/host/linux-x86:all"))) + // This should be parameterized on the host OS, but let's restrict to linux + // to keep things simple for now. + cmdFlags = append(cmdFlags, + fmt.Sprintf("--host_platform=%s", canonicalizeLabel("//build/bazel/platforms:linux_x86_64"))) + // Explicitly disable downloading rules (such as canonical C++ and Java rules) from the network. cmdFlags = append(cmdFlags, "--experimental_repository_disable_download") cmdFlags = append(cmdFlags, extraFlags...) @@ -332,8 +319,13 @@ local_repository( name = "sourceroot", path = "%s", ) + +local_repository( + name = "rules_cc", + path = "%s/build/bazel/rules_cc", +) ` - return []byte(fmt.Sprintf(formatString, context.workspaceDir)) + return []byte(fmt.Sprintf(formatString, context.workspaceDir, context.workspaceDir)) } func (context *bazelContext) mainBzlFileContents() []byte { @@ -344,73 +336,39 @@ func (context *bazelContext) mainBzlFileContents() []byte { # This file is generated by soong_build. Do not edit. ##################################################### -def _x86_64_transition_impl(settings, attr): - return { - "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_x86_64", - } - -def _x86_transition_impl(settings, attr): - return { - "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_x86", - } - -def _arm64_transition_impl(settings, attr): - return { - "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_arm64", - } - -def _arm_transition_impl(settings, attr): +def _config_node_transition_impl(settings, attr): return { - "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:generic_arm", + "//command_line_option:platforms": "@sourceroot//build/bazel/platforms:android_%s" % attr.arch, } -x86_64_transition = transition( - implementation = _x86_64_transition_impl, +_config_node_transition = transition( + implementation = _config_node_transition_impl, inputs = [], outputs = [ "//command_line_option:platforms", ], ) -x86_transition = transition( - implementation = _x86_transition_impl, - inputs = [], - outputs = [ - "//command_line_option:platforms", - ], -) +def _passthrough_rule_impl(ctx): + return [DefaultInfo(files = depset(ctx.files.deps))] -arm64_transition = transition( - implementation = _arm64_transition_impl, - inputs = [], - outputs = [ - "//command_line_option:platforms", - ], -) - -arm_transition = transition( - implementation = _arm_transition_impl, - inputs = [], - outputs = [ - "//command_line_option:platforms", - ], +config_node = rule( + implementation = _passthrough_rule_impl, + attrs = { + "arch" : attr.string(mandatory = True), + "deps" : attr.label_list(cfg = _config_node_transition), + "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + }, ) -def _mixed_build_root_impl(ctx): - all_files = ctx.files.deps_x86_64 + ctx.files.deps_x86 + ctx.files.deps_arm64 + ctx.files.deps_arm - return [DefaultInfo(files = depset(all_files))] # Rule representing the root of the build, to depend on all Bazel targets that # are required for the build. Building this target will build the entire Bazel # build tree. mixed_build_root = rule( - implementation = _mixed_build_root_impl, + implementation = _passthrough_rule_impl, attrs = { - "deps_x86_64" : attr.label_list(cfg = x86_64_transition), - "deps_x86" : attr.label_list(cfg = x86_transition), - "deps_arm64" : attr.label_list(cfg = arm64_transition), - "deps_arm" : attr.label_list(cfg = arm_transition), - "_allowlist_function_transition": attr.label(default = "@bazel_tools//tools/allowlists/function_transition_allowlist"), + "deps" : attr.label_list(), }, ) @@ -446,44 +404,42 @@ func (context *bazelContext) mainBuildFileContents() []byte { // architecture mapping. formatString := ` # This file is generated by soong_build. Do not edit. -load(":main.bzl", "mixed_build_root", "phony_root") +load(":main.bzl", "config_node", "mixed_build_root", "phony_root") + +%s mixed_build_root(name = "buildroot", - deps_x86_64 = [%s], - deps_x86 = [%s], - deps_arm64 = [%s], - deps_arm = [%s], + deps = [%s], ) phony_root(name = "phonyroot", deps = [":buildroot"], ) ` - var deps_x86_64 []string = nil - var deps_x86 []string = nil - var deps_arm64 []string = nil - var deps_arm []string = nil + configNodeFormatString := ` +config_node(name = "%s", + arch = "%s", + deps = [%s], +) +` + + configNodesSection := "" + + labelsByArch := map[string][]string{} for val, _ := range context.requests { labelString := fmt.Sprintf("\"%s\"", canonicalizeLabel(val.label)) - switch getArchString(val) { - case "x86_64": - deps_x86_64 = append(deps_x86_64, labelString) - case "x86": - deps_x86 = append(deps_x86, labelString) - case "arm64": - deps_arm64 = append(deps_arm64, labelString) - case "arm": - deps_arm = append(deps_arm, labelString) - default: - panic(fmt.Sprintf("unhandled architecture %s for %v", getArchString(val), val)) - } + archString := getArchString(val) + labelsByArch[archString] = append(labelsByArch[archString], labelString) } - return []byte(fmt.Sprintf(formatString, - strings.Join(deps_x86_64, ",\n "), - strings.Join(deps_x86, ",\n "), - strings.Join(deps_arm64, ",\n "), - strings.Join(deps_arm, ",\n "))) + configNodeLabels := []string{} + for archString, labels := range labelsByArch { + configNodeLabels = append(configNodeLabels, fmt.Sprintf("\":%s\"", archString)) + labelsString := strings.Join(labels, ",\n ") + configNodesSection += fmt.Sprintf(configNodeFormatString, archString, archString, labelsString) + } + + return []byte(fmt.Sprintf(formatString, configNodesSection, strings.Join(configNodeLabels, ",\n "))) } func indent(original string) string { @@ -558,10 +514,10 @@ def get_arch(target): platform_name = build_options(target)["//command_line_option:platforms"][0].name if platform_name == "host": return "HOST" - elif not platform_name.startswith("generic_"): - fail("expected platform name of the form 'generic_<arch>', but was " + str(platforms)) + elif not platform_name.startswith("android_"): + fail("expected platform name of the form 'android_<arch>', but was " + str(platforms)) return "UNKNOWN" - return platform_name[len("generic_"):] + return platform_name[len("android_"):] def format(target): id_string = str(target.label) + "|" + get_arch(target) @@ -746,6 +702,10 @@ func (c *bazelSingleton) GenerateBuildActions(ctx SingletonContext) { cmd.Implicit(PathForBazelOut(ctx, inputPath)) } + if depfile := buildStatement.Depfile; depfile != nil { + cmd.ImplicitDepFile(PathForBazelOut(ctx, *depfile)) + } + // This is required to silence warnings pertaining to unexpected timestamps. Particularly, // some Bazel builtins (such as files in the bazel_tools directory) have far-future // timestamps. Without restat, Ninja would emit warnings that the input files of a diff --git a/android/filegroup.go b/android/filegroup.go index abbb4d424..2f13ab891 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -30,7 +30,7 @@ var PrepareForTestWithFilegroup = FixtureRegisterWithContext(func(ctx Registrati // https://docs.bazel.build/versions/master/be/general.html#filegroup type bazelFilegroupAttributes struct { - Srcs bazel.LabelList + Srcs bazel.LabelListAttribute } type bazelFilegroup struct { @@ -57,8 +57,10 @@ func FilegroupBp2Build(ctx TopDownMutatorContext) { return } + srcs := bazel.MakeLabelListAttribute( + BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs)) attrs := &bazelFilegroupAttributes{ - Srcs: BazelLabelForModuleSrcExcludes(ctx, fg.properties.Srcs, fg.properties.Exclude_srcs), + Srcs: srcs, } props := bazel.BazelTargetModuleProperties{Rule_class: "filegroup"} diff --git a/android/fixture.go b/android/fixture.go index 8d629582d..5fc668a8b 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -26,16 +26,9 @@ import ( // Fixture // ======= // These determine the environment within which a test can be run. Fixtures are mutable and are -// created by FixtureFactory instances and mutated by FixturePreparer instances. They are created by -// first creating a base Fixture (which is essentially empty) and then applying FixturePreparer -// instances to it to modify the environment. -// -// FixtureFactory (deprecated) -// =========================== -// These are responsible for creating fixtures. Factories are immutable and are intended to be -// initialized once and reused to create multiple fixtures. Each factory has a list of fixture -// preparers that prepare a fixture for running a test. Factories can also be used to create other -// factories by extending them with additional fixture preparers. +// created and mutated by FixturePreparer instances. They are created by first creating a base +// Fixture (which is essentially empty) and then applying FixturePreparer instances to it to modify +// the environment. // // FixturePreparer // =============== @@ -169,77 +162,6 @@ import ( // PrepareForApex, // ) // -// // FixtureFactory instances have been deprecated, this remains for informational purposes to -// // help explain some of the existing code but will be removed along with FixtureFactory. -// -// var javaFixtureFactory = android.NewFixtureFactory( -// PrepareForIntegrationTestWithJava, -// FixtureRegisterWithContext(func(ctx android.RegistrationContext) { -// ctx.RegisterModuleType("test_module", testModule) -// }), -// javaMockFS.AddToFixture(), -// ... -// } -// -// func TestJavaStuff(t *testing.T) { -// result := javaFixtureFactory.RunTest(t, -// android.FixtureWithRootAndroidBp(`java_library {....}`), -// android.MockFS{...}.AddToFixture(), -// ) -// ... test result ... -// } -// -// package cc -// var PrepareForTestWithCC = GroupFixturePreparers( -// android.PrepareForArchMutator, -// android.prepareForPrebuilts, -// FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest), -// ... -// ) -// -// package apex -// -// var PrepareForApex = GroupFixturePreparers( -// ... -// ) -// -// Use modules and mutators from java, cc and apex. Any duplicate preparers (like -// android.PrepareForArchMutator) will be automatically deduped. -// -// var apexFixtureFactory = android.NewFixtureFactory( -// PrepareForJava, -// PrepareForCC, -// PrepareForApex, -// ) - -// Factory for Fixture objects. -// -// This is configured with a set of FixturePreparer objects that are used to -// initialize each Fixture instance this creates. -// -// deprecated: Use FixturePreparer instead. -type FixtureFactory interface { - FixturePreparer -} - -// Create a new FixtureFactory that will apply the supplied preparers. -// -// The buildDirSupplier is a pointer to the package level buildDir variable that is initialized by -// the package level setUp method. It has to be a pointer to the variable as the variable will not -// have been initialized at the time the factory is created. If it is nil then a test specific -// temporary directory will be created instead. -// -// deprecated: The functionality provided by FixtureFactory will be merged into FixturePreparer -func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory { - f := &fixtureFactory{ - buildDirSupplier: buildDirSupplier, - compositeFixturePreparer: compositeFixturePreparer{ - preparers: dedupAndFlattenPreparers(nil, preparers), - }, - } - f.initBaseFixturePreparer(f) - return f -} // A set of mock files to add to the mock file system. type MockFS map[string][]byte @@ -445,17 +367,8 @@ type FixturePreparer interface { // Return the flattened and deduped list of simpleFixturePreparer pointers. list() []*simpleFixturePreparer - // Creates a copy of this instance and adds some additional preparers. - // - // Before the preparers are used they are combined with the preparers provided when the factory - // was created, any groups of preparers are flattened, and the list is deduped so that each - // preparer is only used once. See the file documentation in android/fixture.go for more details. - // - // deprecated: Use GroupFixturePreparers() instead. - Extend(preparers ...FixturePreparer) FixturePreparer - // Create a Fixture. - Fixture(t *testing.T, preparers ...FixturePreparer) Fixture + Fixture(t *testing.T) Fixture // ExtendWithErrorHandler creates a new FixturePreparer that will use the supplied error handler // to check the errors (may be 0) reported by the test. @@ -466,12 +379,13 @@ type FixturePreparer interface { // Run the test, checking any errors reported and returning a TestResult instance. // - // Shorthand for Fixture(t, preparers...).RunTest() - RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult + // Shorthand for Fixture(t).RunTest() + RunTest(t *testing.T) *TestResult // Run the test with the supplied Android.bp file. // - // Shorthand for RunTest(t, android.FixtureWithRootAndroidBp(bp)) + // preparer.RunTestWithBp(t, bp) is shorthand for + // android.GroupFixturePreparers(preparer, android.FixtureWithRootAndroidBp(bp)).RunTest(t) RunTestWithBp(t *testing.T, bp string) *TestResult // RunTestWithConfig is a temporary method added to help ease the migration of existing tests to @@ -705,13 +619,11 @@ type TestResult struct { NinjaDeps []string } -func createFixture(t *testing.T, buildDir string, base []*simpleFixturePreparer, extra []FixturePreparer) Fixture { - all := dedupAndFlattenPreparers(base, extra) - +func createFixture(t *testing.T, buildDir string, preparers []*simpleFixturePreparer) Fixture { config := TestConfig(buildDir, nil, "", nil) ctx := NewTestContext(config) fixture := &fixture{ - preparers: all, + preparers: preparers, t: t, config: config, ctx: ctx, @@ -720,7 +632,7 @@ func createFixture(t *testing.T, buildDir string, base []*simpleFixturePreparer, errorHandler: FixtureExpectsNoErrors, } - for _, preparer := range all { + for _, preparer := range preparers { preparer.function(fixture) } @@ -735,30 +647,25 @@ func (b *baseFixturePreparer) initBaseFixturePreparer(self FixturePreparer) { b.self = self } -func (b *baseFixturePreparer) Extend(preparers ...FixturePreparer) FixturePreparer { - all := dedupAndFlattenPreparers(b.self.list(), preparers) - return newFixturePreparer(all) -} - -func (b *baseFixturePreparer) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture { - return createFixture(t, t.TempDir(), b.self.list(), preparers) +func (b *baseFixturePreparer) Fixture(t *testing.T) Fixture { + return createFixture(t, t.TempDir(), b.self.list()) } func (b *baseFixturePreparer) ExtendWithErrorHandler(errorHandler FixtureErrorHandler) FixturePreparer { - return b.self.Extend(newSimpleFixturePreparer(func(fixture *fixture) { + return GroupFixturePreparers(b.self, newSimpleFixturePreparer(func(fixture *fixture) { fixture.errorHandler = errorHandler })) } -func (b *baseFixturePreparer) RunTest(t *testing.T, preparers ...FixturePreparer) *TestResult { +func (b *baseFixturePreparer) RunTest(t *testing.T) *TestResult { t.Helper() - fixture := b.self.Fixture(t, preparers...) + fixture := b.self.Fixture(t) return fixture.RunTest() } func (b *baseFixturePreparer) RunTestWithBp(t *testing.T, bp string) *TestResult { t.Helper() - return b.RunTest(t, FixtureWithRootAndroidBp(bp)) + return GroupFixturePreparers(b.self, FixtureWithRootAndroidBp(bp)).RunTest(t) } func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *TestResult { @@ -783,46 +690,6 @@ func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *Te return fixture.RunTest() } -var _ FixtureFactory = (*fixtureFactory)(nil) - -type fixtureFactory struct { - compositeFixturePreparer - - buildDirSupplier *string -} - -// Override to preserve the buildDirSupplier. -func (f *fixtureFactory) Extend(preparers ...FixturePreparer) FixturePreparer { - // If there is no buildDirSupplier then just use the default implementation. - if f.buildDirSupplier == nil { - return f.baseFixturePreparer.Extend(preparers...) - } - - all := dedupAndFlattenPreparers(f.preparers, preparers) - - // Create a new factory which uses the same buildDirSupplier as the previous one. - extendedFactory := &fixtureFactory{ - buildDirSupplier: f.buildDirSupplier, - compositeFixturePreparer: compositeFixturePreparer{ - preparers: all, - }, - } - extendedFactory.initBaseFixturePreparer(extendedFactory) - return extendedFactory -} - -func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture { - // If there is no buildDirSupplier then just use the default implementation. - if f.buildDirSupplier == nil { - return f.baseFixturePreparer.Fixture(t, preparers...) - } - - // Retrieve the buildDir from the supplier. - buildDir := *f.buildDirSupplier - - return createFixture(t, buildDir, f.preparers, preparers) -} - type fixture struct { // The preparers used to create this fixture. preparers []*simpleFixturePreparer @@ -937,10 +804,10 @@ func (r *TestResult) NormalizePathsForTesting(paths Paths) []string { // that produced this result. // // e.g. assuming that this result was created by running: -// factory.Extend(preparer1, preparer2).RunTest(t, preparer3, preparer4) +// GroupFixturePreparers(preparer1, preparer2, preparer3).RunTest(t) // // Then this method will be equivalent to running: -// GroupFixturePreparers(preparer1, preparer2, preparer3, preparer4) +// GroupFixturePreparers(preparer1, preparer2, preparer3) // // This is intended for use by tests whose output is Android.bp files to verify that those files // are valid, e.g. tests of the snapshots produced by the sdk module type. diff --git a/android/fixture_test.go b/android/fixture_test.go index 681a03427..5b810e0b7 100644 --- a/android/fixture_test.go +++ b/android/fixture_test.go @@ -41,45 +41,42 @@ func TestFixtureDedup(t *testing.T) { group := GroupFixturePreparers(preparer1, preparer2, preparer1, preparer1Then2) - extension := group.Extend(preparer4, preparer2) + extension := GroupFixturePreparers(group, preparer4, preparer2) - extension.Fixture(t, preparer1, preparer2, preparer2Then1, preparer3) + GroupFixturePreparers(extension, preparer1, preparer2, preparer2Then1, preparer3).Fixture(t) AssertDeepEquals(t, "preparers called in wrong order", []string{"preparer1", "preparer2", "preparer4", "preparer3"}, list) } func TestFixtureValidateMockFS(t *testing.T) { - buildDir := "<unused>" - factory := NewFixtureFactory(&buildDir) - t.Run("absolute path", func(t *testing.T) { AssertPanicMessageContains(t, "source path validation failed", "Path is outside directory: /abs/path/Android.bp", func() { - factory.Fixture(t, FixtureAddFile("/abs/path/Android.bp", nil)) + FixtureAddFile("/abs/path/Android.bp", nil).Fixture(t) }) }) t.Run("not canonical", func(t *testing.T) { AssertPanicMessageContains(t, "source path validation failed", `path "path/with/../in/it/Android.bp" is not a canonical path, use "path/in/it/Android.bp" instead`, func() { - factory.Fixture(t, FixtureAddFile("path/with/../in/it/Android.bp", nil)) + FixtureAddFile("path/with/../in/it/Android.bp", nil).Fixture(t) }) }) t.Run("FixtureAddFile", func(t *testing.T) { AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() { - factory.Fixture(t, FixtureAddFile("out/Android.bp", nil)) + FixtureAddFile("out/Android.bp", nil).Fixture(t) }) }) t.Run("FixtureMergeMockFs", func(t *testing.T) { AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() { - factory.Fixture(t, FixtureMergeMockFs(MockFS{ + FixtureMergeMockFs(MockFS{ "out/Android.bp": nil, - })) + }).Fixture(t) }) }) t.Run("FixtureModifyMockFS", func(t *testing.T) { AssertPanicMessageContains(t, "source path validation failed", `cannot add output path "out/Android.bp" to the mock file system`, func() { - factory.Fixture(t, FixtureModifyMockFS(func(fs MockFS) { + FixtureModifyMockFS(func(fs MockFS) { fs["out/Android.bp"] = nil - })) + }).Fixture(t) }) }) } diff --git a/android/mutator.go b/android/mutator.go index 9e99beeef..e25e2e8f1 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -202,7 +202,7 @@ var postDeps = []RegisterMutatorFunc{ RegisterPrebuiltsPostDepsMutators, RegisterVisibilityRuleEnforcer, RegisterLicensesDependencyChecker, - RegisterNeverallowMutator, + registerNeverallowMutator, RegisterOverridePostDepsMutators, } @@ -539,7 +539,7 @@ func (t *topDownMutatorContext) CreateBazelTargetModule( Name: &name, } - b := t.CreateModule(factory, &nameProp, attrs).(BazelTargetModule) + b := t.createModuleWithoutInheritance(factory, &nameProp, attrs).(BazelTargetModule) b.SetBazelTargetModuleProperties(bazelProps) return b } @@ -608,6 +608,11 @@ func (t *topDownMutatorContext) CreateModule(factory ModuleFactory, props ...int return module } +func (t *topDownMutatorContext) createModuleWithoutInheritance(factory ModuleFactory, props ...interface{}) Module { + module := t.bp.CreateModule(ModuleFactoryAdaptor(factory), props...).(Module) + return module +} + func (b *bottomUpMutatorContext) MutatorName() string { return b.bp.MutatorName() } diff --git a/android/neverallow.go b/android/neverallow.go index 7455e6a78..a385bbc0c 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -42,7 +42,7 @@ import ( // counts as a match // - it has none of the "Without" properties matched (same rules as above) -func RegisterNeverallowMutator(ctx RegisterMutatorsContext) { +func registerNeverallowMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("neverallow", neverallowMutator).Parallel() } @@ -661,6 +661,22 @@ func neverallowRules(config Config) []Rule { // Overrides the default neverallow rules for the supplied config. // // For testing only. -func SetTestNeverallowRules(config Config, testRules []Rule) { +func setTestNeverallowRules(config Config, testRules []Rule) { config.Once(neverallowRulesKey, func() interface{} { return testRules }) } + +// Prepares for a test by setting neverallow rules and enabling the mutator. +// +// If the supplied rules are nil then the default rules are used. +func PrepareForTestWithNeverallowRules(testRules []Rule) FixturePreparer { + return GroupFixturePreparers( + FixtureModifyConfig(func(config Config) { + if testRules != nil { + setTestNeverallowRules(config, testRules) + } + }), + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.PostDepsMutators(registerNeverallowMutator) + }), + ) +} diff --git a/android/neverallow_test.go b/android/neverallow_test.go index de0197a80..268346a7b 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -292,7 +292,6 @@ var prepareForNeverAllowTest = GroupFixturePreparers( ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) ctx.RegisterModuleType("makefile_goal", newMockMakefileGoalModule) - ctx.PostDepsMutators(RegisterNeverallowMutator) }), ) @@ -301,12 +300,7 @@ func TestNeverallow(t *testing.T) { t.Run(test.name, func(t *testing.T) { GroupFixturePreparers( prepareForNeverAllowTest, - FixtureModifyConfig(func(config Config) { - // If the test has its own rules then use them instead of the default ones. - if test.rules != nil { - SetTestNeverallowRules(config, test.rules) - } - }), + PrepareForTestWithNeverallowRules(test.rules), test.fs.AddToFixture(), ). ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). diff --git a/android/paths.go b/android/paths.go index b4573728a..ba1ab1138 100644 --- a/android/paths.go +++ b/android/paths.go @@ -286,6 +286,16 @@ func (p OptionalPath) Path() Path { return p.path } +// RelativeToTop returns an OptionalPath with the path that was embedded having been replaced by the +// result of calling Path.RelativeToTop on it. +func (p OptionalPath) RelativeToTop() OptionalPath { + if !p.valid { + return p + } + p.path = p.path.RelativeToTop() + return p +} + // String returns the string version of the Path, or "" if it isn't valid. func (p OptionalPath) String() string { if p.valid { @@ -477,6 +487,9 @@ func expandSrcsForBazel(ctx BazelConversionPathContext, paths, expandedExcludes // already be resolved by either deps mutator or path deps mutator. func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string) bazel.Label { m, _ := ctx.GetDirectDep(dep) + if m == nil { + panic(fmt.Errorf("cannot get direct dep %s of %s", dep, ctx.Module().Name())) + } otherLabel := bazelModuleLabel(ctx, m, tag) label := bazelModuleLabel(ctx, ctx.Module(), "") if samePackage(label, otherLabel) { diff --git a/android/queryview.go b/android/queryview.go index 12d14dfb6..224652eba 100644 --- a/android/queryview.go +++ b/android/queryview.go @@ -68,7 +68,7 @@ func generateBuildActionsForBazelConversion(ctx SingletonContext, converterMode Command: fmt.Sprintf( `rm -rf "${outDir}/"* && `+ `mkdir -p "${outDir}" && `+ - `echo WORKSPACE: cat "%s" > "${outDir}/.queryview-depfile.d" && `+ + `echo WORKSPACE: $$(cat "%s") > "${outDir}/.queryview-depfile.d" && `+ `BUILDER="%s" && `+ `echo BUILDER=$$BUILDER && `+ `cd "$$(dirname "$$BUILDER")" && `+ diff --git a/android/register.go b/android/register.go index 35469d476..4c8088d0c 100644 --- a/android/register.go +++ b/android/register.go @@ -192,6 +192,15 @@ 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/rule_builder_test.go b/android/rule_builder_test.go index 9c5ca4148..d2a7d8d2a 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -645,7 +645,7 @@ func TestRuleBuilder_Build(t *testing.T) { rspFile := "out/soong/.intermediates/foo/rsp" rspFile2 := "out/soong/.intermediates/foo/rsp2" module := result.ModuleForTests("foo", "") - check(t, module.Rule("rule").RelativeToTop(), module.Output(rspFile2).RelativeToTop(), + check(t, module.Rule("rule"), module.Output(rspFile2), "cp bar "+outFile+" @"+rspFile+" @"+rspFile2, outFile, outFile+".d", rspFile, rspFile2, true, nil, nil) }) @@ -662,7 +662,7 @@ func TestRuleBuilder_Build(t *testing.T) { cmd := `rm -rf ` + outDir + `/gen && ` + sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest module := result.ModuleForTests("foo_sbox", "") - check(t, module.Output("gen/foo_sbox").RelativeToTop(), module.Output(rspFile2).RelativeToTop(), + check(t, module.Output("gen/foo_sbox"), module.Output(rspFile2), cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox}) }) t.Run("sbox_inputs", func(t *testing.T) { @@ -679,7 +679,7 @@ func TestRuleBuilder_Build(t *testing.T) { sbox + ` --sandbox-path ` + sandboxPath + ` --manifest ` + manifest module := result.ModuleForTests("foo_sbox_inputs", "") - check(t, module.Output("gen/foo_sbox_inputs").RelativeToTop(), module.Output(rspFile2).RelativeToTop(), + check(t, module.Output("gen/foo_sbox_inputs"), module.Output(rspFile2), cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox}) }) t.Run("singleton", func(t *testing.T) { @@ -687,7 +687,7 @@ func TestRuleBuilder_Build(t *testing.T) { rspFile := filepath.Join("out/soong/singleton/rsp") rspFile2 := filepath.Join("out/soong/singleton/rsp2") singleton := result.SingletonForTests("rule_builder_test") - check(t, singleton.Rule("rule").RelativeToTop(), singleton.Output(rspFile2).RelativeToTop(), + check(t, singleton.Rule("rule"), singleton.Output(rspFile2), "cp bar "+outFile+" @"+rspFile+" @"+rspFile2, outFile, outFile+".d", rspFile, rspFile2, true, nil, nil) }) diff --git a/android/sdk_version.go b/android/sdk_version.go new file mode 100644 index 000000000..ce22b5f46 --- /dev/null +++ b/android/sdk_version.go @@ -0,0 +1,311 @@ +// 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" + "strconv" + "strings" +) + +type SdkContext interface { + // SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module + SdkVersion() SdkSpec + // SystemModules returns the system_modules property of the current module, or an empty string if it is not set. + SystemModules() string + // MinSdkVersion returns SdkSpec that corresponds to the min_sdk_version property of the current module, + // or from sdk_version if it is not set. + MinSdkVersion() SdkSpec + // TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module, + // or from sdk_version if it is not set. + TargetSdkVersion() SdkSpec +} + +// SdkKind represents a particular category of an SDK spec like public, system, test, etc. +type SdkKind int + +const ( + SdkInvalid SdkKind = iota + SdkNone + SdkCore + SdkCorePlatform + SdkPublic + SdkSystem + SdkTest + SdkModule + SdkSystemServer + SdkPrivate +) + +// String returns the string representation of this SdkKind +func (k SdkKind) String() string { + switch k { + case SdkPrivate: + return "private" + case SdkNone: + return "none" + case SdkPublic: + return "public" + case SdkSystem: + return "system" + case SdkTest: + return "test" + case SdkCore: + return "core" + case SdkCorePlatform: + return "core_platform" + case SdkModule: + return "module-lib" + case SdkSystemServer: + return "system-server" + default: + return "invalid" + } +} + +// SdkVersion represents a specific version number of an SDK spec of a particular kind +type SdkVersion int + +const ( + // special version number for a not-yet-frozen SDK + SdkVersionCurrent SdkVersion = SdkVersion(FutureApiLevelInt) + // special version number to be used for SDK specs where version number doesn't + // make sense, e.g. "none", "", etc. + SdkVersionNone SdkVersion = SdkVersion(0) +) + +// IsCurrent checks if the SdkVersion refers to the not-yet-published version of an SdkKind +func (v SdkVersion) IsCurrent() bool { + return v == SdkVersionCurrent +} + +// IsNumbered checks if the SdkVersion refers to the published (a.k.a numbered) version of an SdkKind +func (v SdkVersion) IsNumbered() bool { + return !v.IsCurrent() && v != SdkVersionNone +} + +// String returns the string representation of this SdkVersion. +func (v SdkVersion) String() string { + if v.IsCurrent() { + return "current" + } else if v.IsNumbered() { + return strconv.Itoa(int(v)) + } + return "(no version)" +} + +func (v SdkVersion) ApiLevel(ctx EarlyModuleContext) ApiLevel { + return ApiLevelOrPanic(ctx, v.String()) +} + +// AsNumberString directly converts the numeric value of this sdk version as a string. +// When isNumbered() is true, this method is the same as String(). However, for SdkVersionCurrent +// and SdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"), +// respectively. +func (v SdkVersion) AsNumberString() string { + return strconv.Itoa(int(v)) +} + +// SdkSpec represents the kind and the version of an SDK for a module to build against +type SdkSpec struct { + Kind SdkKind + Version SdkVersion + Raw string +} + +func (s SdkSpec) String() string { + return fmt.Sprintf("%s_%s", s.Kind, s.Version) +} + +// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the +// specified SDK actually exists. +func (s SdkSpec) Valid() bool { + return s.Kind != SdkInvalid +} + +// Specified checks if this SdkSpec is well-formed and is not "". +func (s SdkSpec) Specified() bool { + return s.Valid() && s.Kind != SdkPrivate +} + +// whether the API surface is managed and versioned, i.e. has .txt file that +// get frozen on SDK freeze and changes get reviewed by API council. +func (s SdkSpec) Stable() bool { + if !s.Specified() { + return false + } + switch s.Kind { + case SdkNone: + // there is nothing to manage and version in this case; de facto stable API. + return true + case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer: + return true + case SdkCorePlatform, SdkTest, SdkPrivate: + return false + default: + panic(fmt.Errorf("unknown SdkKind=%v", s.Kind)) + } + return false +} + +// PrebuiltSdkAvailableForUnbundledBuilt 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 + // as we don't/can't have prebuilt stub for the versions + return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform +} + +func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec { + // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, + // use it instead of "current" for the vendor partition. + currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() + if currentSdkVersion == "current" { + return s + } + + if s.Kind == SdkPublic || s.Kind == SdkSystem { + if s.Version.IsCurrent() { + if i, err := strconv.Atoi(currentSdkVersion); err == nil { + version := SdkVersion(i) + return SdkSpec{s.Kind, version, s.Raw} + } + panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) + } + } + return s +} + +// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context. +func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool { + if s.Version.IsCurrent() { + // "current" can be built from source and be from prebuilt SDK + return ctx.Config().AlwaysUsePrebuiltSdks() + } else if s.Version.IsNumbered() { + // validation check + if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule { + panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind)) + return false + } + // numbered SDKs are always from prebuilt + return true + } + // "", "none", "core_platform" fall here + return false +} + +// EffectiveVersion converts an SdkSpec into the concrete SdkVersion that the module +// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) +// it returns FutureApiLevel(10000). +func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (SdkVersion, error) { + if !s.Valid() { + return s.Version, fmt.Errorf("invalid sdk version %q", s.Raw) + } + + if ctx.DeviceSpecific() || ctx.SocSpecific() { + s = s.ForVendorPartition(ctx) + } + if s.Version.IsNumbered() { + return s.Version, nil + } + return SdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil +} + +// EffectiveVersionString converts an SdkSpec into the concrete version string that the module +// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) +// it returns the codename (P, Q, R, etc.) +func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) { + ver, err := s.EffectiveVersion(ctx) + if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() { + return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil + } + return ver.String(), err +} + +func SdkSpecFrom(str string) SdkSpec { + switch str { + // special cases first + case "": + return SdkSpec{SdkPrivate, SdkVersionNone, str} + case "none": + return SdkSpec{SdkNone, SdkVersionNone, str} + case "core_platform": + return SdkSpec{SdkCorePlatform, SdkVersionNone, str} + default: + // the syntax is [kind_]version + sep := strings.LastIndex(str, "_") + + var kindString string + if sep == 0 { + return SdkSpec{SdkInvalid, SdkVersionNone, str} + } else if sep == -1 { + kindString = "" + } else { + kindString = str[0:sep] + } + versionString := str[sep+1 : len(str)] + + var kind SdkKind + switch kindString { + case "": + kind = SdkPublic + case "core": + kind = SdkCore + case "system": + kind = SdkSystem + case "test": + kind = SdkTest + case "module": + kind = SdkModule + case "system_server": + kind = SdkSystemServer + default: + return SdkSpec{SdkInvalid, SdkVersionNone, str} + } + + var version SdkVersion + if versionString == "current" { + version = SdkVersionCurrent + } else if i, err := strconv.Atoi(versionString); err == nil { + version = SdkVersion(i) + } else { + return SdkSpec{SdkInvalid, SdkVersionNone, str} + } + + return SdkSpec{kind, version, str} + } +} + +func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool { + // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module) + // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29, + // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current + if s.Kind != SdkSystem || !s.Version.IsNumbered() { + return true + } + allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions() + if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { + systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions() + if len(systemSdkVersions) > 0 { + allowedVersions = systemSdkVersions + } + } + if len(allowedVersions) > 0 && !InList(s.Version.String(), allowedVersions) { + ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", + s.Raw, allowedVersions) + return false + } + return true +} diff --git a/android/testing.go b/android/testing.go index 27573d5d8..ce27fca04 100644 --- a/android/testing.go +++ b/android/testing.go @@ -551,6 +551,8 @@ type TestingBuildParams struct { // * CommandOrderOnly // // See PathRelativeToTop for more details. +// +// deprecated: this is no longer needed as TestingBuildParams are created in this form. func (p TestingBuildParams) RelativeToTop() TestingBuildParams { // If this is not a valid params then just return it back. That will make it easy to use with the // Maybe...() methods. @@ -558,7 +560,7 @@ func (p TestingBuildParams) RelativeToTop() TestingBuildParams { return p } if p.config.config == nil { - panic("cannot call RelativeToTop() on a TestingBuildParams previously returned by RelativeToTop()") + return p } // Take a copy of the build params and replace any args that contains test specific temporary // paths with paths relative to the top. @@ -670,7 +672,7 @@ func (b baseTestingComponent) newTestingBuildParams(bparams BuildParams) Testing config: b.config, BuildParams: bparams, RuleParams: b.provider.RuleParamsForTests()[bparams.Rule], - } + }.RelativeToTop() } func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuildParams, []string) { @@ -816,6 +818,22 @@ func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string { return normalizeStringMapRelativeToTop(m.config, m.module.VariablesForTests()) } +// OutputFiles calls OutputFileProducer.OutputFiles on the encapsulated module, exits the test +// immediately if there is an error and otherwise returns the result of calling Paths.RelativeToTop +// on the returned Paths. +func (m TestingModule) OutputFiles(t *testing.T, tag string) Paths { + producer, ok := m.module.(OutputFileProducer) + if !ok { + t.Fatalf("%q must implement OutputFileProducer\n", m.module.Name()) + } + paths, err := producer.OutputFiles(tag) + if err != nil { + t.Fatal(err) + } + + return paths.RelativeToTop() +} + // TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual // ctx.Build parameters for verification in tests. type TestingSingleton struct { @@ -1040,3 +1058,20 @@ func StringPathsRelativeToTop(soongOutDir string, paths []string) []string { } return result } + +// StringRelativeToTop will normalize a string containing paths, e.g. ninja command, by replacing +// any references to the test specific temporary build directory that changes with each run to a +// fixed path relative to a notional top directory. +// +// This is similar to StringPathRelativeToTop except that assumes the string is a single path +// containing at most one instance of the temporary build directory at the start of the path while +// this assumes that there can be any number at any position. +func StringRelativeToTop(config Config, command string) string { + return normalizeStringRelativeToTop(config, command) +} + +// StringsRelativeToTop will return a new slice such that each item in the new slice is the result +// of calling StringRelativeToTop on the corresponding item in the input slice. +func StringsRelativeToTop(config Config, command []string) []string { + return normalizeStringArrayRelativeToTop(config, command) +} diff --git a/android/variable.go b/android/variable.go index 2ab51c74a..dff48c289 100644 --- a/android/variable.go +++ b/android/variable.go @@ -448,6 +448,63 @@ func (v *productVariables) SetDefaultConfig() { } } +// ProductConfigContext requires the access to the Module to get product config properties. +type ProductConfigContext interface { + Module() Module +} + +// ProductConfigProperty contains the information for a single property (may be a struct) paired +// with the appropriate ProductConfigVariable. +type ProductConfigProperty struct { + ProductConfigVariable string + Property interface{} +} + +// ProductConfigProperties is a map of property name to a slice of ProductConfigProperty such that +// all it all product variable-specific versions of a property are easily accessed together +type ProductConfigProperties map[string][]ProductConfigProperty + +// ProductVariableProperties returns a ProductConfigProperties containing only the properties which +// have been set for the module in the given context. +func ProductVariableProperties(ctx ProductConfigContext) ProductConfigProperties { + module := ctx.Module() + moduleBase := module.base() + + productConfigProperties := ProductConfigProperties{} + + if moduleBase.variableProperties == nil { + return productConfigProperties + } + + variableValues := reflect.ValueOf(moduleBase.variableProperties).Elem().FieldByName("Product_variables") + for i := 0; i < variableValues.NumField(); i++ { + variableValue := variableValues.Field(i) + // Check if any properties were set for the module + if variableValue.IsZero() { + continue + } + // e.g. Platform_sdk_version, Unbundled_build, Malloc_not_svelte, etc. + productVariableName := variableValues.Type().Field(i).Name + for j := 0; j < variableValue.NumField(); j++ { + property := variableValue.Field(j) + // If the property wasn't set, no need to pass it along + if property.IsZero() { + continue + } + + // e.g. Asflags, Cflags, Enabled, etc. + propertyName := variableValue.Type().Field(j).Name + productConfigProperties[propertyName] = append(productConfigProperties[propertyName], + ProductConfigProperty{ + ProductConfigVariable: productVariableName, + Property: property.Interface(), + }) + } + } + + return productConfigProperties +} + func VariableMutator(mctx BottomUpMutatorContext) { var module Module var ok bool diff --git a/apex/apex.go b/apex/apex.go index 80d961561..9d06e1c8f 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -1702,6 +1702,9 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, af) } } + + // Track transitive dependencies. + return true } case javaLibTag: switch child.(type) { @@ -1910,6 +1913,21 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesInfo = append(filesInfo, af) return true // track transitive dependencies } + } else if java.IsbootImageContentDepTag(depTag) { + // Add the contents of the boot image to the apex. + switch child.(type) { + case *java.Library, *java.SdkLibrary: + af := apexFileForJavaModule(ctx, child.(javaModule)) + if !af.ok() { + ctx.PropertyErrorf("boot_images", "boot image content %q is not configured to be compiled into dex", depName) + return false + } + filesInfo = append(filesInfo, af) + return true // track transitive dependencies + default: + ctx.PropertyErrorf("boot_images", "boot image content %q of type %q is not supported", depName, ctx.OtherModuleType(child)) + } + } else if _, ok := depTag.(android.CopyDirectlyInAnyApexTag); ok { // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { diff --git a/apex/apex_test.go b/apex/apex_test.go index 37db5d86f..98b40fd5b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -16,13 +16,13 @@ package apex import ( "fmt" - "io/ioutil" "os" "path" "path/filepath" "reflect" "regexp" "sort" + "strconv" "strings" "testing" @@ -38,8 +38,6 @@ import ( "android/soong/sh" ) -var buildDir string - // names returns name list from white space separated string func names(s string) (ns []string) { for _, n := range strings.Split(s, " ") { @@ -52,18 +50,28 @@ func names(s string) (ns []string) { func testApexError(t *testing.T, pattern, bp string, preparers ...android.FixturePreparer) { t.Helper() - apexFixtureFactory.Extend(preparers...). + android.GroupFixturePreparers( + prepareForApexTest, + android.GroupFixturePreparers(preparers...), + ). ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). RunTestWithBp(t, bp) } func testApex(t *testing.T, bp string, preparers ...android.FixturePreparer) *android.TestContext { t.Helper() - factory := apexFixtureFactory.Extend(preparers...) + + optionalBpPreparer := android.NullFixturePreparer if bp != "" { - factory = factory.Extend(android.FixtureWithRootAndroidBp(bp)) + optionalBpPreparer = android.FixtureWithRootAndroidBp(bp) } - result := factory.RunTest(t) + + result := android.GroupFixturePreparers( + prepareForApexTest, + android.GroupFixturePreparers(preparers...), + optionalBpPreparer, + ).RunTest(t) + return result.TestContext } @@ -117,8 +125,16 @@ var withUnbundledBuild = android.FixtureModifyProductVariables( }, ) -var apexFixtureFactory = android.NewFixtureFactory( - &buildDir, +// Legacy preparer used for running tests within the apex package. +// +// This includes everything that was needed to run any test in the apex package prior to the +// introduction of the test fixtures. Tests that are being converted to use fixtures directly +// rather than through the testApex...() methods should avoid using this and instead use the +// various preparers directly, using android.GroupFixturePreparers(...) to group them when +// necessary. +// +// deprecated +var prepareForApexTest = android.GroupFixturePreparers( // General preparers in alphabetical order as test infrastructure will enforce correct // registration order. android.PrepareForTestWithAndroidBuildComponents, @@ -208,18 +224,6 @@ var prepareForTestWithMyapex = android.FixtureMergeMockFs(android.MockFS{ "system/sepolicy/apex/myapex-file_contexts": nil, }) -func setUp() { - var err error - buildDir, err = ioutil.TempDir("", "soong_apex_test") - if err != nil { - panic(err) - } -} - -func tearDown() { - _ = os.RemoveAll(buildDir) -} - // ensure that 'result' equals 'expected' func ensureEquals(t *testing.T, result string, expected string) { t.Helper() @@ -515,7 +519,7 @@ func TestBasicApex(t *testing.T) { optFlags := apexRule.Args["opt_flags"] ensureContains(t, optFlags, "--pubkey vendor/foo/devkeys/testkey.avbpubkey") // Ensure that the NOTICE output is being packaged as an asset. - ensureContains(t, optFlags, "--assets_dir "+buildDir+"/.intermediates/myapex/android_common_myapex_image/NOTICE") + ensureContains(t, optFlags, "--assets_dir out/soong/.intermediates/myapex/android_common_myapex_image/NOTICE") copyCmds := apexRule.Args["copy_commands"] @@ -816,7 +820,7 @@ func TestApexWithStubs(t *testing.T) { mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 - ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so") + ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") @@ -1294,15 +1298,15 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { name: "unspecified version links to the latest", minSdkVersion: "", apexVariant: "apex10000", - shouldLink: "30", - shouldNotLink: []string{"29"}, + shouldLink: "current", + shouldNotLink: []string{"29", "30"}, }, { name: "always use the latest", minSdkVersion: "min_sdk_version: \"29\",", apexVariant: "apex29", - shouldLink: "30", - shouldNotLink: []string{"29"}, + shouldLink: "current", + shouldNotLink: []string{"29", "30"}, }, } for _, tc := range testcases { @@ -1369,7 +1373,11 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { } mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] - ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink) + ver := tc.shouldLink + if tc.shouldLink == "current" { + ver = strconv.Itoa(android.FutureApiLevelInt) + } + ensureContains(t, mylibCFlags, "__LIBBAR_API__="+ver) }) } } @@ -1431,12 +1439,12 @@ func TestApexWithSystemLibsStubs(t *testing.T) { // For dependency to libc // Ensure that mylib is linking with the latest version of stubs - ensureContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_29/libc.so") + ensureContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared_current/libc.so") // ... and not linking to the non-stub (impl) variant ensureNotContains(t, mylibLdFlags, "libc/android_arm64_armv8-a_shared/libc.so") // ... Cflags from stub is correctly exported to mylib - ensureContains(t, mylibCFlags, "__LIBC_API__=29") - ensureContains(t, mylibSharedCFlags, "__LIBC_API__=29") + ensureContains(t, mylibCFlags, "__LIBC_API__=10000") + ensureContains(t, mylibSharedCFlags, "__LIBC_API__=10000") // For dependency to libm // Ensure that mylib is linking with the non-stub (impl) variant @@ -1542,12 +1550,14 @@ func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) } // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") - // liba in myapex is linked to #30 - expectLink("liba", "shared_apex29", "libz", "shared_30") + // liba in myapex is linked to current + expectLink("liba", "shared_apex29", "libz", "shared_current") + expectNoLink("liba", "shared_apex29", "libz", "shared_30") expectNoLink("liba", "shared_apex29", "libz", "shared_28") expectNoLink("liba", "shared_apex29", "libz", "shared") - // liba in otherapex is linked to #30 - expectLink("liba", "shared_apex30", "libz", "shared_30") + // liba in otherapex is linked to current + expectLink("liba", "shared_apex30", "libz", "shared_current") + expectNoLink("liba", "shared_apex30", "libz", "shared_30") expectNoLink("liba", "shared_apex30", "libz", "shared_28") expectNoLink("liba", "shared_apex30", "libz", "shared") } @@ -1598,7 +1608,8 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_apex10000", "libz", "shared_R") + expectLink("libx", "shared_apex10000", "libz", "shared_current") + expectNoLink("libx", "shared_apex10000", "libz", "shared_R") expectNoLink("libx", "shared_apex10000", "libz", "shared_29") expectNoLink("libx", "shared_apex10000", "libz", "shared") } @@ -1644,8 +1655,9 @@ func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_apex10000", "libz", "shared_2") + expectLink("libx", "shared_apex10000", "libz", "shared_current") expectNoLink("libx", "shared_apex10000", "libz", "shared_1") + expectNoLink("libx", "shared_apex10000", "libz", "shared_2") expectNoLink("libx", "shared_apex10000", "libz", "shared") } @@ -1692,7 +1704,8 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libz", "shared", "libx", "shared_2") + expectLink("libz", "shared", "libx", "shared_current") + expectNoLink("libz", "shared", "libx", "shared_2") expectNoLink("libz", "shared", "libz", "shared_1") expectNoLink("libz", "shared", "libz", "shared") } @@ -1739,7 +1752,7 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_30") + expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_current") } func TestQTargetApexUsesStaticUnwinder(t *testing.T) { @@ -1823,6 +1836,30 @@ func TestApexMinSdkVersion_ErrorIfIncompatibleVersion(t *testing.T) { min_sdk_version: "30", } `) + + testApexError(t, `module "libfoo".*: should support min_sdk_version\(29\)`, ` + apex { + name: "myapex", + key: "myapex.key", + java_libs: ["libfoo"], + min_sdk_version: "29", + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + java_import { + name: "libfoo", + jars: ["libfoo.jar"], + apex_available: [ + "myapex", + ], + min_sdk_version: "30", + } + `) } func TestApexMinSdkVersion_Okay(t *testing.T) { @@ -1860,7 +1897,10 @@ func TestApexMinSdkVersion_Okay(t *testing.T) { name: "libbar", sdk_version: "current", srcs: ["a.java"], - static_libs: ["libbar_dep"], + static_libs: [ + "libbar_dep", + "libbar_import_dep", + ], apex_available: ["myapex"], min_sdk_version: "29", } @@ -1872,6 +1912,13 @@ func TestApexMinSdkVersion_Okay(t *testing.T) { apex_available: ["myapex"], min_sdk_version: "29", } + + java_import { + name: "libbar_import_dep", + jars: ["libbar.jar"], + apex_available: ["myapex"], + min_sdk_version: "29", + } `) } @@ -2087,7 +2134,7 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion private_key: "testkey.pem", } - // mylib in myapex will link to mylib2#30 + // mylib in myapex will link to mylib2#current // mylib in otherapex will link to mylib2(non-stub) in otherapex as well cc_library { name: "mylib", @@ -2121,7 +2168,7 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } - expectLink("mylib", "shared_apex29", "mylib2", "shared_30") + expectLink("mylib", "shared_apex29", "mylib2", "shared_current") expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30") } @@ -2189,10 +2236,10 @@ func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) { } `, withSAsActiveCodeNames) - // ensure libfoo is linked with "S" version of libbar stub + // ensure libfoo is linked with current version of libbar stub libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex10000") libFlags := libfoo.Rule("ld").Args["libFlags"] - ensureContains(t, libFlags, "android_arm64_armv8-a_shared_T/libbar.so") + ensureContains(t, libFlags, "android_arm64_armv8-a_shared_current/libbar.so") } func TestFilesInSubDir(t *testing.T) { @@ -2468,8 +2515,8 @@ func TestVendorApex(t *testing.T) { prefix := "TARGET_" var builder strings.Builder data.Custom(&builder, name, prefix, "", data) - androidMk := builder.String() - installPath := path.Join(buildDir, "../target/product/test_device/vendor/apex") + androidMk := android.StringRelativeToTop(ctx.Config(), builder.String()) + installPath := "out/target/product/test_device/vendor/apex" ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath) apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Rule("apexManifestRule") @@ -2516,10 +2563,10 @@ func TestVendorApex_use_vndk_as_stable(t *testing.T) { ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld") libs := names(ldRule.Args["libFlags"]) // VNDK libs(libvndk/libc++) as they are - ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so") - ensureListContains(t, libs, buildDir+"/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"libc++/"+vendorVariant+"_shared/libc++.so") + ensureListContains(t, libs, "out/soong/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so") + ensureListContains(t, libs, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"libc++/"+vendorVariant+"_shared/libc++.so") // non-stable Vendor libs as APEX variants - ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so") + ensureListContains(t, libs, "out/soong/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so") // VNDK libs are not included when use_vndk_as_stable: true ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{ @@ -4092,15 +4139,15 @@ func TestApexInVariousPartition(t *testing.T) { `) apex := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) - expected := buildDir + "/target/product/test_device/" + tc.parition + "/apex" - actual := apex.installDir.String() + expected := "out/soong/target/product/test_device/" + tc.parition + "/apex" + actual := apex.installDir.RelativeToTop().String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } flattened := ctx.ModuleForTests("myapex", "android_common_myapex_flattened").Module().(*apexBundle) - expected = buildDir + "/target/product/test_device/" + tc.flattenedPartition + "/apex" - actual = flattened.installDir.String() + expected = "out/soong/target/product/test_device/" + tc.flattenedPartition + "/apex" + actual = flattened.installDir.RelativeToTop().String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) } @@ -4494,14 +4541,11 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { if filepath.Base(output) == base { foundLibfooJar = true buildRule := s.Output(output) - actual := android.NormalizePathForTesting(buildRule.Input) - if actual != bootDexJarPath { - t.Errorf("Incorrect boot dex jar path '%s', expected '%s'", actual, bootDexJarPath) - } + android.AssertStringEquals(t, "boot dex jar path", bootDexJarPath, buildRule.Input.String()) } } if !foundLibfooJar { - t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs") + t.Errorf("Rule for libfoo.jar missing in dex_bootjars singleton outputs %q", android.StringPathsRelativeToTop(ctx.Config().BuildDir(), s.AllOutputs())) } } @@ -4543,8 +4587,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", transform) - checkBootDexJarPath(t, ctx, "libfoo", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. checkHiddenAPIIndexInputs(t, ctx, ` @@ -4650,8 +4694,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", transform) - checkBootDexJarPath(t, ctx, "libfoo", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. checkHiddenAPIIndexInputs(t, ctx, ` @@ -4717,8 +4761,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", transform) - checkBootDexJarPath(t, ctx, "libfoo", ".intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", ".intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/libfoo/android_common_apex10000/hiddenapi/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/libbar/android_common_myapex/hiddenapi/libbar.jar") // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. checkHiddenAPIIndexInputs(t, ctx, ` @@ -4786,8 +4830,8 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { ` ctx := testDexpreoptWithApexes(t, bp, "", transform) - checkBootDexJarPath(t, ctx, "libfoo", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") - checkBootDexJarPath(t, ctx, "libbar", ".intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") + checkBootDexJarPath(t, ctx, "libfoo", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libfoo.jar") + checkBootDexJarPath(t, ctx, "libbar", "out/soong/.intermediates/myapex.deapexer/android_common/deapexer/javalib/libbar.jar") // Make sure that the dex file from the prebuilt_apex contributes to the hiddenapi index file. checkHiddenAPIIndexInputs(t, ctx, ` @@ -5081,7 +5125,7 @@ func TestApexWithApps(t *testing.T) { } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile() + jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile().RelativeToTop() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX @@ -5719,7 +5763,7 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { // The bar library should depend on the implementation jar. barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } @@ -5770,7 +5814,7 @@ func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { // The bar library should depend on the stubs jar. barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } @@ -5860,7 +5904,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { // The bar library should depend on the implementation jar. barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") - if expected, actual := `^-classpath /[^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.impl\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } @@ -5893,9 +5937,10 @@ func TestJavaSDKLibrary_ImportOnly(t *testing.T) { } func TestCompatConfig(t *testing.T) { - result := apexFixtureFactory. - Extend(java.PrepareForTestWithPlatformCompatConfig). - RunTestWithBp(t, ` + result := android.GroupFixturePreparers( + prepareForApexTest, + java.PrepareForTestWithPlatformCompatConfig, + ).RunTestWithBp(t, ` apex { name: "myapex", key: "myapex.key", @@ -6331,7 +6376,7 @@ func TestAppSetBundlePrebuilt(t *testing.T) { ) m := ctx.ModuleForTests("myapex", "android_common") - extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex") + extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex") actual := extractedApex.Inputs if len(actual) != 1 { @@ -6438,68 +6483,46 @@ func testNoUpdatableJarsInBootImage(t *testing.T, errmsg string, transformDexpre func testDexpreoptWithApexes(t *testing.T, bp, errmsg string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) *android.TestContext { t.Helper() - bp += cc.GatherRequiredDepsForTest(android.Android) - bp += java.GatherRequiredDepsForTest() - - fs := map[string][]byte{ - "a.java": nil, - "a.jar": nil, - "build/make/target/product/security": nil, - "apex_manifest.json": nil, - "AndroidManifest.xml": nil, + fs := android.MockFS{ + "a.java": nil, + "a.jar": nil, + "apex_manifest.json": nil, + "AndroidManifest.xml": nil, "system/sepolicy/apex/myapex-file_contexts": nil, "system/sepolicy/apex/some-updatable-apex-file_contexts": nil, "system/sepolicy/apex/some-non-updatable-apex-file_contexts": nil, "system/sepolicy/apex/com.android.art.debug-file_contexts": nil, "framework/aidl/a.aidl": nil, } - cc.GatherRequiredFilesForTest(fs) - for k, v := range filesForSdkLibrary { - fs[k] = v - } - config := android.TestArchConfig(buildDir, nil, bp, fs) - - ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.RegisterModuleType("prebuilt_apex", PrebuiltFactory) - ctx.RegisterModuleType("filegroup", android.FileGroupFactory) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - ctx.PreArchMutators(android.RegisterComponentsMutator) - android.RegisterPrebuiltMutators(ctx) - cc.RegisterRequiredBuildComponentsForTest(ctx) - java.RegisterRequiredBuildComponentsForTest(ctx) - java.RegisterHiddenApiSingletonComponents(ctx) - ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) - - ctx.Register() - - pathCtx := android.PathContextForTesting(config) - dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) - transformDexpreoptConfig(dexpreoptConfig) - dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) - - // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding - // product variables. - config.TestProductVariables.BootJars = dexpreoptConfig.BootJars - config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars - - _, errs := ctx.ParseBlueprintsFiles("Android.bp") - android.FailIfErrored(t, errs) - - _, errs = ctx.PrepareBuildActions(config) - if errmsg == "" { - android.FailIfErrored(t, errs) - } else if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, errmsg, errs) - } else { - t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) + errorHandler := android.FixtureExpectsNoErrors + if errmsg != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(errmsg) } - return ctx + result := android.GroupFixturePreparers( + cc.PrepareForTestWithCcDefaultModules, + java.PrepareForTestWithHiddenApiBuildComponents, + java.PrepareForTestWithJavaDefaultModules, + java.PrepareForTestWithJavaSdkLibraryFiles, + PrepareForTestWithApexBuildComponents, + android.FixtureModifyConfig(func(config android.Config) { + pathCtx := android.PathContextForTesting(config) + dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx) + transformDexpreoptConfig(dexpreoptConfig) + dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig) + + // Make sure that any changes to these dexpreopt properties are mirrored in the corresponding + // product variables. + config.TestProductVariables.BootJars = dexpreoptConfig.BootJars + config.TestProductVariables.UpdatableBootJars = dexpreoptConfig.UpdatableBootJars + }), + fs.AddToFixture(), + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, bp) + + return result.TestContext } func TestUpdatable_should_set_min_sdk_version(t *testing.T) { @@ -6673,45 +6696,33 @@ func testApexPermittedPackagesRules(t *testing.T, errmsg, bp string, apexBootJar public_key: "testkey.avbpubkey", private_key: "testkey.pem", }` - fs := map[string][]byte{ + fs := android.MockFS{ "lib1/src/A.java": nil, "lib2/src/B.java": nil, "system/sepolicy/apex/myapex-file_contexts": nil, } - config := android.TestArchConfig(buildDir, nil, bp, fs) - android.SetTestNeverallowRules(config, rules) - updatableBootJars := make([]string, 0, len(apexBootJars)) - for _, apexBootJar := range apexBootJars { - updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) - } - config.TestProductVariables.UpdatableBootJars = android.CreateTestConfiguredJarList(updatableBootJars) - - ctx := android.NewTestArchContext(config) - ctx.RegisterModuleType("apex", BundleFactory) - ctx.RegisterModuleType("apex_key", ApexKeyFactory) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - cc.RegisterRequiredBuildComponentsForTest(ctx) - java.RegisterRequiredBuildComponentsForTest(ctx) - ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators) - ctx.PreDepsMutators(RegisterPreDepsMutators) - ctx.PostDepsMutators(RegisterPostDepsMutators) - ctx.PostDepsMutators(android.RegisterNeverallowMutator) - - ctx.Register() - - _, errs := ctx.ParseBlueprintsFiles("Android.bp") - android.FailIfErrored(t, errs) - - _, errs = ctx.PrepareBuildActions(config) - if errmsg == "" { - android.FailIfErrored(t, errs) - } else if len(errs) > 0 { - android.FailIfNoMatchingErrors(t, errmsg, errs) - return - } else { - t.Fatalf("missing expected error %q (0 errors are returned)", errmsg) + errorHandler := android.FixtureExpectsNoErrors + if errmsg != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(errmsg) } + + android.GroupFixturePreparers( + android.PrepareForTestWithAndroidBuildComponents, + java.PrepareForTestWithJavaBuildComponents, + PrepareForTestWithApexBuildComponents, + android.PrepareForTestWithNeverallowRules(rules), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + updatableBootJars := make([]string, 0, len(apexBootJars)) + for _, apexBootJar := range apexBootJars { + updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar) + } + variables.UpdatableBootJars = android.CreateTestConfiguredJarList(updatableBootJars) + }), + fs.AddToFixture(), + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, bp) } func TestApexPermittedPackagesRules(t *testing.T) { @@ -6864,7 +6875,7 @@ func TestTestFor(t *testing.T) { `) ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) { - ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ") + ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ") mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) }) android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags) } @@ -6922,7 +6933,7 @@ func TestIndirectTestFor(t *testing.T) { `) ensureLinkedLibIs := func(mod, variant, linkedLib, expectedVariant string) { - ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").RelativeToTop().Args["libFlags"], " ") + ldFlags := strings.Split(ctx.ModuleForTests(mod, variant).Rule("ld").Args["libFlags"], " ") mylibLdFlags := android.FilterListPred(ldFlags, func(s string) bool { return strings.HasPrefix(s, linkedLib) }) android.AssertArrayString(t, "unexpected "+linkedLib+" link library for "+mod, []string{linkedLib + expectedVariant}, mylibLdFlags) } @@ -6964,7 +6975,7 @@ func TestApexSet(t *testing.T) { m := ctx.ModuleForTests("myapex", "android_common") // Check extract_apks tool parameters. - extractedApex := m.Output(buildDir + "/.intermediates/myapex/android_common/foo_v2.apex") + extractedApex := m.Output("out/soong/.intermediates/myapex/android_common/foo_v2.apex") actual := extractedApex.Args["abis"] expected := "ARMEABI_V7A,ARM64_V8A" if actual != expected { @@ -7443,7 +7454,7 @@ func TestPrebuiltStubLibDep(t *testing.T) { t.Errorf("AndroidMk entry for \"stublib\" has LOCAL_NOT_AVAILABLE_FOR_PLATFORM set: %+v", entry.mkEntries) } cflags := entry.mkEntries.EntryMap["LOCAL_EXPORT_CFLAGS"] - expected := "-D__STUBLIB_API__=1" + expected := "-D__STUBLIB_API__=10000" if !android.InList(expected, cflags) { t.Errorf("LOCAL_EXPORT_CFLAGS expected to have %q, but got %q", expected, cflags) } @@ -7455,12 +7466,5 @@ func TestPrebuiltStubLibDep(t *testing.T) { } func TestMain(m *testing.M) { - run := func() int { - setUp() - defer tearDown() - - return m.Run() - } - - os.Exit(run()) + os.Exit(m.Run()) } diff --git a/apex/boot_image_test.go b/apex/boot_image_test.go index 678a4cdda..574166a53 100644 --- a/apex/boot_image_test.go +++ b/apex/boot_image_test.go @@ -177,8 +177,10 @@ func TestBootImageInArtApex(t *testing.T) { boot_images: [ "mybootimage", ], + // bar (like foo) should be transitively included in this apex because it is part of the + // mybootimage boot_image. However, it is kept here to ensure that the apex dedups the files + // correctly. java_libs: [ - "foo", "bar", ], updatable: false, @@ -247,7 +249,6 @@ func TestBootImageInArtApex(t *testing.T) { java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art_image", []string{ `bar`, `com.android.art.key`, - `foo`, `mybootimage`, }) } @@ -315,4 +316,67 @@ func TestBootImageInPrebuiltArtApex(t *testing.T) { }) } +func TestBootImageContentsNoName(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForTestWithBootImage, + prepareForTestWithMyapex, + ).RunTestWithBp(t, ` + apex { + name: "myapex", + key: "myapex.key", + boot_images: [ + "mybootimage", + ], + 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", + ], + } + + java_library { + name: "bar", + srcs: ["b.java"], + installable: true, + apex_available: [ + "myapex", + ], + } + + boot_image { + name: "mybootimage", + contents: [ + "foo", + "bar", + ], + apex_available: [ + "myapex", + ], + } + `) + + ensureExactContents(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + // This does not include art, oat or vdex files as they are only included for the art boot + // image. + "javalib/bar.jar", + "javalib/foo.jar", + }) + + java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex_image", []string{ + `myapex.key`, + `mybootimage`, + }) +} + // TODO(b/177892522) - add test for host apex. diff --git a/apex/builder.go b/apex/builder.go index da800d4dc..2df380b5a 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -950,6 +950,10 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { if v := m.MinSdkVersion(); v != "" { toMinSdkVersion = v } + } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok { + if v := m.MinSdkVersionString(); v != "" { + toMinSdkVersion = v + } } depInfos[to.Name()] = android.ApexModuleDepInfo{ diff --git a/bazel/aquery.go b/bazel/aquery.go index c82b464ad..555f1dcb4 100644 --- a/bazel/aquery.go +++ b/bazel/aquery.go @@ -74,6 +74,7 @@ type actionGraphContainer struct { // with a Bazel action from Bazel's action graph. type BuildStatement struct { Command string + Depfile *string OutputPaths []string InputPaths []string Env []KeyValuePair @@ -133,12 +134,22 @@ func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) { continue } outputPaths := []string{} + var depfile *string for _, outputId := range actionEntry.OutputIds { outputPath, exists := artifactIdToPath[outputId] if !exists { return nil, fmt.Errorf("undefined outputId %d", outputId) } - outputPaths = append(outputPaths, outputPath) + ext := filepath.Ext(outputPath) + if ext == ".d" { + if depfile != nil { + return nil, fmt.Errorf("found multiple potential depfiles %q, %q", *depfile, outputPath) + } else { + depfile = &outputPath + } + } else { + outputPaths = append(outputPaths, outputPath) + } } inputPaths := []string{} for _, inputDepSetId := range actionEntry.InputDepSetIds { @@ -161,12 +172,13 @@ func AqueryBuildStatements(aqueryJsonProto []byte) ([]BuildStatement, error) { } buildStatement := BuildStatement{ Command: strings.Join(proptools.ShellEscapeList(actionEntry.Arguments), " "), + Depfile: depfile, OutputPaths: outputPaths, InputPaths: inputPaths, Env: actionEntry.EnvironmentVariables, Mnemonic: actionEntry.Mnemonic} if len(actionEntry.Arguments) < 1 { - return nil, fmt.Errorf("received action with no command: [%s]", buildStatement) + return nil, fmt.Errorf("received action with no command: [%v]", buildStatement) continue } buildStatements = append(buildStatements, buildStatement) diff --git a/bazel/aquery_test.go b/bazel/aquery_test.go index a48e0834a..fa8810f0d 100644 --- a/bazel/aquery_test.go +++ b/bazel/aquery_test.go @@ -393,6 +393,109 @@ func TestInvalidPathFragmentId(t *testing.T) { assertError(t, err, "undefined path fragment id 3") } +func TestDepfiles(t *testing.T) { + const inputString = ` +{ + "artifacts": [{ + "id": 1, + "pathFragmentId": 1 + }, { + "id": 2, + "pathFragmentId": 2 + }, { + "id": 3, + "pathFragmentId": 3 + }], + "actions": [{ + "targetId": 1, + "actionKey": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "inputDepSetIds": [1], + "outputIds": [2, 3], + "primaryOutputId": 2 + }], + "depSetOfFiles": [{ + "id": 1, + "directArtifactIds": [1, 2, 3] + }], + "pathFragments": [{ + "id": 1, + "label": "one" + }, { + "id": 2, + "label": "two" + }, { + "id": 3, + "label": "two.d" + }] +}` + + actual, err := AqueryBuildStatements([]byte(inputString)) + if err != nil { + t.Errorf("Unexpected error %q", err) + } + if expected := 1; len(actual) != expected { + t.Fatalf("Expected %d build statements, got %d", expected, len(actual)) + } + + bs := actual[0] + expectedDepfile := "two.d" + if bs.Depfile == nil { + t.Errorf("Expected depfile %q, but there was none found", expectedDepfile) + } else if *bs.Depfile != expectedDepfile { + t.Errorf("Expected depfile %q, but got %q", expectedDepfile, *bs.Depfile) + } +} + +func TestMultipleDepfiles(t *testing.T) { + const inputString = ` +{ + "artifacts": [{ + "id": 1, + "pathFragmentId": 1 + }, { + "id": 2, + "pathFragmentId": 2 + }, { + "id": 3, + "pathFragmentId": 3 + }, { + "id": 4, + "pathFragmentId": 4 + }], + "actions": [{ + "targetId": 1, + "actionKey": "x", + "mnemonic": "x", + "arguments": ["touch", "foo"], + "inputDepSetIds": [1], + "outputIds": [2,3,4], + "primaryOutputId": 2 + }], + "depSetOfFiles": [{ + "id": 1, + "directArtifactIds": [1, 2, 3, 4] + }], + "pathFragments": [{ + "id": 1, + "label": "one" + }, { + "id": 2, + "label": "two" + }, { + "id": 3, + "label": "two.d" + }, { + "id": 4, + "label": "other.d" + }] +}` + + _, err := AqueryBuildStatements([]byte(inputString)) + assertError(t, err, `found multiple potential depfiles "two.d", "other.d"`) +} + func TestTransitiveInputDepsets(t *testing.T) { // The input aquery for this test comes from a proof-of-concept starlark rule which registers // a single action with many inputs given via a deep depset. @@ -627,7 +730,7 @@ func assertError(t *testing.T, err error, expected string) { // Build statement equivalence is determined using buildStatementEquals. func assertBuildStatements(t *testing.T, expected []BuildStatement, actual []BuildStatement) { if len(expected) != len(actual) { - t.Errorf("expected %d build statements, but got %d,\n expected: %s,\n actual: %s", + t.Errorf("expected %d build statements, but got %d,\n expected: %v,\n actual: %v", len(expected), len(actual), expected, actual) return } @@ -638,7 +741,7 @@ ACTUAL_LOOP: continue ACTUAL_LOOP } } - t.Errorf("unexpected build statement %s.\n expected: %s", + t.Errorf("unexpected build statement %v.\n expected: %v", actualStatement, expected) return } diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go index 864db3d2d..bd1ece177 100644 --- a/bazel/cquery/request_type.go +++ b/bazel/cquery/request_type.go @@ -6,7 +6,6 @@ import ( var ( GetOutputFiles RequestType = &getOutputFilesRequestType{} - GetCcObjectFiles RequestType = &getCcObjectFilesRequestType{} GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{} ) @@ -16,7 +15,9 @@ type GetOutputFilesAndCcObjectFiles_Result struct { } var RequestTypes []RequestType = []RequestType{ - GetOutputFiles, GetCcObjectFiles, GetOutputFilesAndCcObjectFiles} + GetOutputFiles, + GetOutputFilesAndCcObjectFiles, +} type RequestType interface { // Name returns a string name for this request type. Such request type names must be unique, @@ -55,28 +56,6 @@ func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} { return strings.Split(rawString, ", ") } -type getCcObjectFilesRequestType struct{} - -func (g getCcObjectFilesRequestType) Name() string { - return "getCcObjectFiles" -} - -func (g getCcObjectFilesRequestType) StarlarkFunctionBody() string { - return ` -result = [] -linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list() - -for linker_input in linker_inputs: - for library in linker_input.libraries: - for object in library.objects: - result += [object.path] -return ', '.join(result)` -} - -func (g getCcObjectFilesRequestType) ParseResult(rawString string) interface{} { - return strings.Split(rawString, ", ") -} - type getOutputFilesAndCcObjectFilesType struct{} func (g getOutputFilesAndCcObjectFilesType) Name() string { diff --git a/bazel/properties.go b/bazel/properties.go index abdc1077d..250fea4cd 100644 --- a/bazel/properties.go +++ b/bazel/properties.go @@ -16,6 +16,7 @@ package bazel import ( "fmt" + "regexp" "sort" ) @@ -31,6 +32,8 @@ type BazelTargetModuleProperties struct { const BazelTargetModuleNamePrefix = "__bp2build__" +var productVariableSubstitutionPattern = regexp.MustCompile("%(d|s)") + // Label is used to represent a Bazel compatible Label. Also stores the original bp text to support // string replacement. type Label struct { @@ -76,6 +79,174 @@ func UniqueBazelLabelList(originalLabelList LabelList) LabelList { return uniqueLabelList } +const ( + // ArchType names in arch.go + ARCH_ARM = "arm" + ARCH_ARM64 = "arm64" + ARCH_X86 = "x86" + ARCH_X86_64 = "x86_64" + + // OsType names in arch.go + OS_ANDROID = "android" + OS_DARWIN = "darwin" + OS_FUCHSIA = "fuchsia" + OS_LINUX = "linux_glibc" + OS_LINUX_BIONIC = "linux_bionic" + OS_WINDOWS = "windows" +) + +var ( + // This is the list of architectures with a Bazel config_setting and + // constraint value equivalent. is actually android.ArchTypeList, but the + // android package depends on the bazel package, so a cyclic dependency + // prevents using that here. + selectableArchs = []string{ARCH_X86, ARCH_X86_64, ARCH_ARM, ARCH_ARM64} + + // Likewise, this is the list of target operating systems. + selectableTargetOs = []string{ + OS_ANDROID, + OS_DARWIN, + OS_FUCHSIA, + OS_LINUX, + OS_LINUX_BIONIC, + OS_WINDOWS, + } + + // A map of architectures to the Bazel label of the constraint_value + // for the @platforms//cpu:cpu constraint_setting + PlatformArchMap = map[string]string{ + ARCH_ARM: "//build/bazel/platforms/arch:arm", + ARCH_ARM64: "//build/bazel/platforms/arch:arm64", + ARCH_X86: "//build/bazel/platforms/arch:x86", + ARCH_X86_64: "//build/bazel/platforms/arch:x86_64", + } + + // A map of target operating systems to the Bazel label of the + // constraint_value for the @platforms//os:os constraint_setting + PlatformOsMap = map[string]string{ + OS_ANDROID: "//build/bazel/platforms/os:android", + OS_DARWIN: "//build/bazel/platforms/os:darwin", + OS_FUCHSIA: "//build/bazel/platforms/os:fuchsia", + OS_LINUX: "//build/bazel/platforms/os:linux", + OS_LINUX_BIONIC: "//build/bazel/platforms/os:linux_bionic", + OS_WINDOWS: "//build/bazel/platforms/os:windows", + } +) + +// Arch-specific label_list typed Bazel attribute values. This should correspond +// to the types of architectures supported for compilation in arch.go. +type labelListArchValues struct { + X86 LabelList + X86_64 LabelList + Arm LabelList + Arm64 LabelList + Common LabelList +} + +type labelListOsValues struct { + Android LabelList + Darwin LabelList + Fuchsia LabelList + Linux LabelList + LinuxBionic LabelList + Windows LabelList +} + +// LabelListAttribute is used to represent a list of Bazel labels as an +// attribute. +type LabelListAttribute struct { + // The non-arch specific attribute label list Value. Required. + Value LabelList + + // The arch-specific attribute label list values. Optional. If used, these + // are generated in a select statement and appended to the non-arch specific + // label list Value. + ArchValues labelListArchValues + + // The os-specific attribute label list values. Optional. If used, these + // are generated in a select statement and appended to the non-os specific + // label list Value. + OsValues labelListOsValues +} + +// MakeLabelListAttribute initializes a LabelListAttribute with the non-arch specific value. +func MakeLabelListAttribute(value LabelList) LabelListAttribute { + return LabelListAttribute{Value: UniqueBazelLabelList(value)} +} + +// HasArchSpecificValues returns true if the attribute contains +// architecture-specific label_list values. +func (attrs *LabelListAttribute) HasConfigurableValues() bool { + for _, arch := range selectableArchs { + if len(attrs.GetValueForArch(arch).Includes) > 0 { + return true + } + } + + for _, os := range selectableTargetOs { + if len(attrs.GetValueForOS(os).Includes) > 0 { + return true + } + } + return false +} + +func (attrs *LabelListAttribute) archValuePtrs() map[string]*LabelList { + return map[string]*LabelList{ + ARCH_X86: &attrs.ArchValues.X86, + ARCH_X86_64: &attrs.ArchValues.X86_64, + ARCH_ARM: &attrs.ArchValues.Arm, + ARCH_ARM64: &attrs.ArchValues.Arm64, + } +} + +// GetValueForArch returns the label_list attribute value for an architecture. +func (attrs *LabelListAttribute) GetValueForArch(arch string) LabelList { + var v *LabelList + if v = attrs.archValuePtrs()[arch]; v == nil { + panic(fmt.Errorf("Unknown arch: %s", arch)) + } + return *v +} + +// SetValueForArch sets the label_list attribute value for an architecture. +func (attrs *LabelListAttribute) SetValueForArch(arch string, value LabelList) { + var v *LabelList + if v = attrs.archValuePtrs()[arch]; v == nil { + panic(fmt.Errorf("Unknown arch: %s", arch)) + } + *v = value +} + +func (attrs *LabelListAttribute) osValuePtrs() map[string]*LabelList { + return map[string]*LabelList{ + OS_ANDROID: &attrs.OsValues.Android, + OS_DARWIN: &attrs.OsValues.Darwin, + OS_FUCHSIA: &attrs.OsValues.Fuchsia, + OS_LINUX: &attrs.OsValues.Linux, + OS_LINUX_BIONIC: &attrs.OsValues.LinuxBionic, + OS_WINDOWS: &attrs.OsValues.Windows, + } +} + +// GetValueForOS returns the label_list attribute value for an OS target. +func (attrs *LabelListAttribute) GetValueForOS(os string) LabelList { + var v *LabelList + if v = attrs.osValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + return *v +} + +// SetValueForArch sets the label_list attribute value for an OS target. +func (attrs *LabelListAttribute) SetValueForOS(os string, value LabelList) { + var v *LabelList + if v = attrs.osValuePtrs()[os]; v == nil { + panic(fmt.Errorf("Unknown os: %s", os)) + } + *v = value +} + // StringListAttribute corresponds to the string_list Bazel attribute type with // support for additional metadata, like configurations. type StringListAttribute struct { @@ -89,19 +260,17 @@ type StringListAttribute struct { // Arch-specific string_list typed Bazel attribute values. This should correspond // to the types of architectures supported for compilation in arch.go. type stringListArchValues struct { - X86 []string - X86_64 []string - Arm []string - Arm64 []string - Default []string - // TODO(b/181299724): this is currently missing the "common" arch, which - // doesn't have an equivalent platform() definition yet. + X86 []string + X86_64 []string + Arm []string + Arm64 []string + Common []string } -// HasArchSpecificValues returns true if the attribute contains +// HasConfigurableValues returns true if the attribute contains // architecture-specific string_list values. -func (attrs *StringListAttribute) HasArchSpecificValues() bool { - for _, arch := range []string{"x86", "x86_64", "arm", "arm64", "default"} { +func (attrs *StringListAttribute) HasConfigurableValues() bool { + for _, arch := range selectableArchs { if len(attrs.GetValueForArch(arch)) > 0 { return true } @@ -109,38 +278,49 @@ func (attrs *StringListAttribute) HasArchSpecificValues() bool { return false } +func (attrs *StringListAttribute) archValuePtrs() map[string]*[]string { + return map[string]*[]string{ + ARCH_X86: &attrs.ArchValues.X86, + ARCH_X86_64: &attrs.ArchValues.X86_64, + ARCH_ARM: &attrs.ArchValues.Arm, + ARCH_ARM64: &attrs.ArchValues.Arm64, + } +} + // GetValueForArch returns the string_list attribute value for an architecture. func (attrs *StringListAttribute) GetValueForArch(arch string) []string { - switch arch { - case "x86": - return attrs.ArchValues.X86 - case "x86_64": - return attrs.ArchValues.X86_64 - case "arm": - return attrs.ArchValues.Arm - case "arm64": - return attrs.ArchValues.Arm64 - case "default": - return attrs.ArchValues.Default - default: + var v *[]string + if v = attrs.archValuePtrs()[arch]; v == nil { panic(fmt.Errorf("Unknown arch: %s", arch)) } + return *v } // SetValueForArch sets the string_list attribute value for an architecture. func (attrs *StringListAttribute) SetValueForArch(arch string, value []string) { - switch arch { - case "x86": - attrs.ArchValues.X86 = value - case "x86_64": - attrs.ArchValues.X86_64 = value - case "arm": - attrs.ArchValues.Arm = value - case "arm64": - attrs.ArchValues.Arm64 = value - case "default": - attrs.ArchValues.Default = value - default: + var v *[]string + if v = attrs.archValuePtrs()[arch]; v == nil { panic(fmt.Errorf("Unknown arch: %s", arch)) } + *v = value +} + +// TryVariableSubstitution, replace string substitution formatting within each string in slice with +// Starlark string.format compatible tag for productVariable. +func TryVariableSubstitutions(slice []string, productVariable string) ([]string, bool) { + ret := make([]string, 0, len(slice)) + changesMade := false + for _, s := range slice { + newS, changed := TryVariableSubstitution(s, productVariable) + ret = append(ret, newS) + changesMade = changesMade || changed + } + return ret, changesMade +} + +// TryVariableSubstitution, replace string substitution formatting within s with Starlark +// string.format compatible tag for productVariable. +func TryVariableSubstitution(s string, productVariable string) (string, bool) { + sub := productVariableSubstitutionPattern.ReplaceAllString(s, "{"+productVariable+"}") + return sub, s != sub } diff --git a/bloaty/Android.bp b/bloaty/Android.bp index b1f1e398b..96cc1a519 100644 --- a/bloaty/Android.bp +++ b/bloaty/Android.bp @@ -1,3 +1,7 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + bootstrap_go_package { name: "soong-bloaty", pkgPath: "android/soong/bloaty", diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go index 90bbd4da5..1d254c855 100644 --- a/bp2build/build_conversion.go +++ b/bp2build/build_conversion.go @@ -415,40 +415,12 @@ func prettyPrint(propertyValue reflect.Value, indent int) (string, error) { case reflect.Struct: // Special cases where the bp2build sends additional information to the codegenerator // by wrapping the attributes in a custom struct type. - if labels, ok := propertyValue.Interface().(bazel.LabelList); ok { - // TODO(b/165114590): convert glob syntax - return prettyPrint(reflect.ValueOf(labels.Includes), indent) + if labels, ok := propertyValue.Interface().(bazel.LabelListAttribute); ok { + return prettyPrintLabelListAttribute(labels, indent) } else if label, ok := propertyValue.Interface().(bazel.Label); ok { return fmt.Sprintf("%q", label.Label), nil } else if stringList, ok := propertyValue.Interface().(bazel.StringListAttribute); ok { - // A Bazel string_list attribute that may contain a select statement. - ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent) - if err != nil { - return ret, err - } - - if !stringList.HasArchSpecificValues() { - // Select statement not needed. - return ret, nil - } - - ret += " + " + "select({\n" - for _, arch := range android.ArchTypeList() { - value := stringList.GetValueForArch(arch.Name) - if len(value) > 0 { - ret += makeIndent(indent + 1) - list, _ := prettyPrint(reflect.ValueOf(value), indent+1) - ret += fmt.Sprintf("\"%s\": %s,\n", platformArchMap[arch], list) - } - } - - ret += makeIndent(indent + 1) - list, _ := prettyPrint(reflect.ValueOf(stringList.GetValueForArch("default")), indent+1) - ret += fmt.Sprintf("\"%s\": %s,\n", "//conditions:default", list) - - ret += makeIndent(indent) - ret += "})" - return ret, err + return prettyPrintStringListAttribute(stringList, indent) } ret = "{\n" @@ -544,6 +516,13 @@ func isZero(value reflect.Value) bool { func escapeString(s string) string { s = strings.ReplaceAll(s, "\\", "\\\\") + + // b/184026959: Reverse the application of some common control sequences. + // These must be generated literally in the BUILD file. + s = strings.ReplaceAll(s, "\t", "\\t") + s = strings.ReplaceAll(s, "\n", "\\n") + s = strings.ReplaceAll(s, "\r", "\\r") + return strings.ReplaceAll(s, "\"", "\\\"") } diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go index b9b250a5c..49897b3ca 100644 --- a/bp2build/build_conversion_test.go +++ b/bp2build/build_conversion_test.go @@ -241,6 +241,22 @@ func TestGenerateBazelTargetModules(t *testing.T) { string_prop = "a", )`, }, + { + bp: `custom { + name: "control_characters", + string_list_prop: ["\t", "\n"], + string_prop: "a\t\n\r", + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTarget: `custom( + name = "control_characters", + string_list_prop = [ + "\t", + "\n", + ], + string_prop = "a\t\n\r", +)`, + }, } dir := "." @@ -502,8 +518,6 @@ genrule { expectedBazelTargets: []string{ `filegroup( name = "fg_foo", - srcs = [ - ], )`, }, }, @@ -1101,8 +1115,8 @@ genrule { "out", ], srcs = [ - "srcs-from-3", "in1", + "srcs-from-3", ], )`, description: "genrule applies properties from genrule_defaults transitively", diff --git a/bp2build/cc_library_headers_conversion_test.go b/bp2build/cc_library_headers_conversion_test.go index 049f84a02..d828168ac 100644 --- a/bp2build/cc_library_headers_conversion_test.go +++ b/bp2build/cc_library_headers_conversion_test.go @@ -110,13 +110,11 @@ func TestCcLibraryHeadersBp2Build(t *testing.T) { cc_library_headers { name: "lib-1", export_include_dirs: ["lib-1"], - bazel_module: { bp2build_available: true }, } cc_library_headers { name: "lib-2", export_include_dirs: ["lib-2"], - bazel_module: { bp2build_available: true }, } cc_library_headers { @@ -125,7 +123,6 @@ cc_library_headers { header_libs: ["lib-1", "lib-2"], // TODO: Also support export_header_lib_headers - bazel_module: { bp2build_available: true }, }`, expectedBazelTargets: []string{`cc_library_headers( name = "foo_headers", @@ -163,6 +160,106 @@ cc_library_headers { ], )`}, }, + { + description: "cc_library_headers test with os-specific header_libs props", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + filesystem: map[string]string{}, + bp: soongCcLibraryPreamble + ` +cc_library_headers { name: "android-lib" } +cc_library_headers { name: "base-lib" } +cc_library_headers { name: "darwin-lib" } +cc_library_headers { name: "fuchsia-lib" } +cc_library_headers { name: "linux-lib" } +cc_library_headers { name: "linux_bionic-lib" } +cc_library_headers { name: "windows-lib" } +cc_library_headers { + name: "foo_headers", + header_libs: ["base-lib"], + target: { + android: { header_libs: ["android-lib"] }, + darwin: { header_libs: ["darwin-lib"] }, + fuchsia: { header_libs: ["fuchsia-lib"] }, + linux_bionic: { header_libs: ["linux_bionic-lib"] }, + linux_glibc: { header_libs: ["linux-lib"] }, + windows: { header_libs: ["windows-lib"] }, + }, + bazel_module: { bp2build_available: true }, +}`, + expectedBazelTargets: []string{`cc_library_headers( + name = "android-lib", +)`, `cc_library_headers( + name = "base-lib", +)`, `cc_library_headers( + name = "darwin-lib", +)`, `cc_library_headers( + name = "foo_headers", + deps = [ + ":base-lib", + ] + select({ + "//build/bazel/platforms/os:android": [ + ":android-lib", + ], + "//build/bazel/platforms/os:darwin": [ + ":darwin-lib", + ], + "//build/bazel/platforms/os:fuchsia": [ + ":fuchsia-lib", + ], + "//build/bazel/platforms/os:linux": [ + ":linux-lib", + ], + "//build/bazel/platforms/os:linux_bionic": [ + ":linux_bionic-lib", + ], + "//build/bazel/platforms/os:windows": [ + ":windows-lib", + ], + "//conditions:default": [], + }), +)`, `cc_library_headers( + name = "fuchsia-lib", +)`, `cc_library_headers( + name = "linux-lib", +)`, `cc_library_headers( + name = "linux_bionic-lib", +)`, `cc_library_headers( + name = "windows-lib", +)`}, + }, + { + description: "cc_library_headers test with os-specific header_libs and export_header_lib_headers props", + moduleTypeUnderTest: "cc_library_headers", + moduleTypeUnderTestFactory: cc.LibraryHeaderFactory, + moduleTypeUnderTestBp2BuildMutator: cc.CcLibraryHeadersBp2Build, + depsMutators: []android.RegisterMutatorFunc{cc.RegisterDepsBp2Build}, + filesystem: map[string]string{}, + bp: soongCcLibraryPreamble + ` +cc_library_headers { name: "android-lib" } +cc_library_headers { name: "exported-lib" } +cc_library_headers { + name: "foo_headers", + target: { + android: { header_libs: ["android-lib"], export_header_lib_headers: ["exported-lib"] }, + }, +}`, + expectedBazelTargets: []string{`cc_library_headers( + name = "android-lib", +)`, `cc_library_headers( + name = "exported-lib", +)`, `cc_library_headers( + name = "foo_headers", + deps = [] + select({ + "//build/bazel/platforms/os:android": [ + ":android-lib", + ":exported-lib", + ], + "//conditions:default": [], + }), +)`}, + }, } dir := "." @@ -180,6 +277,9 @@ cc_library_headers { config := android.TestConfig(buildDir, nil, testCase.bp, filesystem) ctx := android.NewTestContext(config) + // TODO(jingwen): make this default for all bp2build tests + ctx.RegisterBp2BuildConfig(bp2buildConfig) + cc.RegisterCCBuildComponents(ctx) ctx.RegisterModuleType("toolchain_library", cc.ToolchainLibraryFactory) diff --git a/bp2build/cc_object_conversion_test.go b/bp2build/cc_object_conversion_test.go index 1c058ba3e..fcc308030 100644 --- a/bp2build/cc_object_conversion_test.go +++ b/bp2build/cc_object_conversion_test.go @@ -74,8 +74,8 @@ func TestCcObjectBp2Build(t *testing.T) { ], srcs = [ "a/b/bar.h", - "a/b/foo.h", "a/b/c.c", + "a/b/foo.h", ], )`, }, @@ -209,6 +209,34 @@ cc_object { )`, }, }, + { + description: "cc_object with product variable", + moduleTypeUnderTest: "cc_object", + moduleTypeUnderTestFactory: cc.ObjectFactory, + moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, + blueprint: `cc_object { + name: "foo", + include_build_directory: false, + product_variables: { + platform_sdk_version: { + asflags: ["-DPLATFORM_SDK_VERSION=%d"], + }, + }, + + bazel_module: { bp2build_available: true }, +} +`, + expectedBazelTargets: []string{`cc_object( + name = "foo", + asflags = [ + "-DPLATFORM_SDK_VERSION={Platform_sdk_version}", + ], + copts = [ + "-fno-addrsig", + ], +)`, + }, + }, } dir := "." @@ -278,9 +306,13 @@ func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) { moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, blueprint: `cc_object { name: "foo", + srcs: ["a.cpp"], arch: { x86: { - cflags: ["-fPIC"], + cflags: ["-fPIC"], // string list + }, + arm: { + srcs: ["arch/arm/file.S"], // label list }, }, bazel_module: { bp2build_available: true }, @@ -292,15 +324,22 @@ func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) { copts = [ "-fno-addrsig", ] + select({ - "@bazel_tools//platforms:x86_32": [ + "//build/bazel/platforms/arch:x86": [ "-fPIC", ], - "//conditions:default": [ - ], + "//conditions:default": [], }), local_include_dirs = [ ".", ], + srcs = [ + "a.cpp", + ] + select({ + "//build/bazel/platforms/arch:arm": [ + "arch/arm/file.S", + ], + "//conditions:default": [], + }), )`, }, }, @@ -311,17 +350,22 @@ func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) { moduleTypeUnderTestBp2BuildMutator: cc.ObjectBp2Build, blueprint: `cc_object { name: "foo", + srcs: ["base.cpp"], arch: { x86: { + srcs: ["x86.cpp"], cflags: ["-fPIC"], }, x86_64: { + srcs: ["x86_64.cpp"], cflags: ["-fPIC"], }, arm: { + srcs: ["arm.cpp"], cflags: ["-Wall"], }, arm64: { + srcs: ["arm64.cpp"], cflags: ["-Wall"], }, }, @@ -334,24 +378,40 @@ func TestCcObjectConfigurableAttributesBp2Build(t *testing.T) { copts = [ "-fno-addrsig", ] + select({ - "@bazel_tools//platforms:arm": [ + "//build/bazel/platforms/arch:arm": [ "-Wall", ], - "@bazel_tools//platforms:aarch64": [ + "//build/bazel/platforms/arch:arm64": [ "-Wall", ], - "@bazel_tools//platforms:x86_32": [ + "//build/bazel/platforms/arch:x86": [ "-fPIC", ], - "@bazel_tools//platforms:x86_64": [ + "//build/bazel/platforms/arch:x86_64": [ "-fPIC", ], - "//conditions:default": [ - ], + "//conditions:default": [], }), local_include_dirs = [ ".", ], + srcs = [ + "base.cpp", + ] + select({ + "//build/bazel/platforms/arch:arm": [ + "arm.cpp", + ], + "//build/bazel/platforms/arch:arm64": [ + "arm64.cpp", + ], + "//build/bazel/platforms/arch:x86": [ + "x86.cpp", + ], + "//build/bazel/platforms/arch:x86_64": [ + "x86_64.cpp", + ], + "//conditions:default": [], + }), )`, }, }, diff --git a/bp2build/configurability.go b/bp2build/configurability.go index 47cf3c612..6ca0d6db1 100644 --- a/bp2build/configurability.go +++ b/bp2build/configurability.go @@ -1,15 +1,112 @@ package bp2build -import "android/soong/android" +import ( + "android/soong/android" + "android/soong/bazel" + "fmt" + "reflect" +) // Configurability support for bp2build. -var ( - // A map of architectures to the Bazel label of the constraint_value. - platformArchMap = map[android.ArchType]string{ - android.Arm: "@bazel_tools//platforms:arm", - android.Arm64: "@bazel_tools//platforms:aarch64", - android.X86: "@bazel_tools//platforms:x86_32", - android.X86_64: "@bazel_tools//platforms:x86_64", +// prettyPrintStringListAttribute converts a StringListAttribute to its Bazel +// syntax. May contain a select statement. +func prettyPrintStringListAttribute(stringList bazel.StringListAttribute, indent int) (string, error) { + ret, err := prettyPrint(reflect.ValueOf(stringList.Value), indent) + if err != nil { + return ret, err } -) + + if !stringList.HasConfigurableValues() { + // Select statement not needed. + return ret, nil + } + + // Create the selects for arch specific values. + selects := map[string]reflect.Value{} + for arch, selectKey := range bazel.PlatformArchMap { + selects[selectKey] = reflect.ValueOf(stringList.GetValueForArch(arch)) + } + + selectMap, err := prettyPrintSelectMap(selects, "[]", indent) + return ret + selectMap, err +} + +// prettyPrintLabelListAttribute converts a LabelListAttribute to its Bazel +// syntax. May contain select statements. +func prettyPrintLabelListAttribute(labels bazel.LabelListAttribute, indent int) (string, error) { + // TODO(b/165114590): convert glob syntax + ret, err := prettyPrint(reflect.ValueOf(labels.Value.Includes), indent) + if err != nil { + return ret, err + } + + if !labels.HasConfigurableValues() { + // Select statements not needed. + return ret, nil + } + + // Create the selects for arch specific values. + archSelects := map[string]reflect.Value{} + for arch, selectKey := range bazel.PlatformArchMap { + archSelects[selectKey] = reflect.ValueOf(labels.GetValueForArch(arch).Includes) + } + selectMap, err := prettyPrintSelectMap(archSelects, "[]", indent) + if err != nil { + return "", err + } + ret += selectMap + + // Create the selects for target os specific values. + osSelects := map[string]reflect.Value{} + for os, selectKey := range bazel.PlatformOsMap { + osSelects[selectKey] = reflect.ValueOf(labels.GetValueForOS(os).Includes) + } + selectMap, err = prettyPrintSelectMap(osSelects, "[]", indent) + return ret + selectMap, err +} + +// prettyPrintSelectMap converts a map of select keys to reflected Values as a generic way +// to construct a select map for any kind of attribute type. +func prettyPrintSelectMap(selectMap map[string]reflect.Value, defaultValue string, indent int) (string, error) { + var selects string + for _, selectKey := range android.SortedStringKeys(selectMap) { + value := selectMap[selectKey] + if isZero(value) { + // Ignore zero values to not generate empty lists. + continue + } + s, err := prettyPrintSelectEntry(value, selectKey, indent) + if err != nil { + return "", err + } + selects += s + ",\n" + } + + if len(selects) == 0 { + // No conditions (or all values are empty lists), so no need for a map. + return "", nil + } + + // Create the map. + ret := " + select({\n" + ret += selects + // default condition comes last. + ret += fmt.Sprintf("%s\"%s\": %s,\n", makeIndent(indent+1), "//conditions:default", defaultValue) + ret += makeIndent(indent) + ret += "})" + + return ret, nil +} + +// prettyPrintSelectEntry converts a reflect.Value into an entry in a select map +// with a provided key. +func prettyPrintSelectEntry(value reflect.Value, key string, indent int) (string, error) { + s := makeIndent(indent + 1) + v, err := prettyPrint(value, indent+1) + if err != nil { + return "", err + } + s += fmt.Sprintf("\"%s\": %s", key, v) + return s, nil +} diff --git a/bp2build/conversion.go b/bp2build/conversion.go index 787222d6e..6b47cd1f1 100644 --- a/bp2build/conversion.go +++ b/bp2build/conversion.go @@ -19,12 +19,13 @@ func CreateBazelFiles( ruleShims map[string]RuleShim, buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile { - files := make([]BazelFile, 0, len(ruleShims)+len(buildToTargets)+numAdditionalFiles) - // Write top level files: WORKSPACE. These files are empty. - files = append(files, newFile("", "WORKSPACE", "")) + var files []BazelFile if mode == QueryView { + // Write top level WORKSPACE. + files = append(files, newFile("", "WORKSPACE", "")) + // Used to denote that the top level directory is a package. files = append(files, newFile("", GeneratedBuildFileName, "")) diff --git a/bp2build/conversion_test.go b/bp2build/conversion_test.go index a115ddcd6..9fd68172c 100644 --- a/bp2build/conversion_test.go +++ b/bp2build/conversion_test.go @@ -24,36 +24,6 @@ type filepath struct { basename string } -func assertFilecountsAreEqual(t *testing.T, actual []BazelFile, expected []filepath) { - if a, e := len(actual), len(expected); a != e { - t.Errorf("Expected %d files, got %d", e, a) - } -} - -func assertFileContent(t *testing.T, actual []BazelFile, expected []filepath) { - for i := range actual { - if g, w := actual[i], expected[i]; g.Dir != w.dir || g.Basename != w.basename { - t.Errorf("Did not find expected file %s/%s", g.Dir, g.Basename) - } else if g.Basename == "BUILD" || g.Basename == "WORKSPACE" { - if g.Contents != "" { - t.Errorf("Expected %s to have no content.", g) - } - } else if g.Contents == "" { - t.Errorf("Contents of %s unexpected empty.", g) - } - } -} - -func sortFiles(files []BazelFile) { - sort.Slice(files, func(i, j int) bool { - if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 { - return files[i].Basename < files[j].Basename - } else { - return dir1 < dir2 - } - }) -} - func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) { files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, QueryView) expectedFilePaths := []filepath{ @@ -79,21 +49,39 @@ func TestCreateBazelFiles_QueryView_AddsTopLevelFiles(t *testing.T) { }, } - assertFilecountsAreEqual(t, files, expectedFilePaths) - sortFiles(files) - assertFileContent(t, files, expectedFilePaths) + // Compare number of files + if a, e := len(files), len(expectedFilePaths); a != e { + t.Errorf("Expected %d files, got %d", e, a) + } + + // Sort the files to be deterministic + sort.Slice(files, func(i, j int) bool { + if dir1, dir2 := files[i].Dir, files[j].Dir; dir1 == dir2 { + return files[i].Basename < files[j].Basename + } else { + return dir1 < dir2 + } + }) + + // Compare the file contents + for i := range files { + actualFile, expectedFile := files[i], expectedFilePaths[i] + + if actualFile.Dir != expectedFile.dir || actualFile.Basename != expectedFile.basename { + t.Errorf("Did not find expected file %s/%s", actualFile.Dir, actualFile.Basename) + } else if actualFile.Basename == "BUILD" || actualFile.Basename == "WORKSPACE" { + if actualFile.Contents != "" { + t.Errorf("Expected %s to have no content.", actualFile) + } + } else if actualFile.Contents == "" { + t.Errorf("Contents of %s unexpected empty.", actualFile) + } + } } -func TestCreateBazelFiles_Bp2Build_AddsTopLevelFiles(t *testing.T) { +func TestCreateBazelFiles_Bp2Build_CreatesNoFilesWithNoTargets(t *testing.T) { files := CreateBazelFiles(map[string]RuleShim{}, map[string]BazelTargets{}, Bp2Build) - expectedFilePaths := []filepath{ - { - dir: "", - basename: "WORKSPACE", - }, + if len(files) != 0 { + t.Errorf("Expected no files, got %d", len(files)) } - - assertFilecountsAreEqual(t, files, expectedFilePaths) - sortFiles(files) - assertFileContent(t, files, expectedFilePaths) } diff --git a/bp2build/testing.go b/bp2build/testing.go index ede804413..ef3a78fd3 100644 --- a/bp2build/testing.go +++ b/bp2build/testing.go @@ -5,6 +5,13 @@ import ( "android/soong/bazel" ) +var ( + // A default configuration for tests to not have to specify bp2build_available on top level targets. + bp2buildConfig = android.Bp2BuildConfig{ + android.BP2BUILD_TOPLEVEL: android.Bp2BuildDefaultTrueRecursively, + } +) + type nestedProps struct { Nested_prop string } diff --git a/cc/Android.bp b/cc/Android.bp index 79e92cb23..cc4d9bc45 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -20,6 +20,7 @@ bootstrap_go_package { "androidmk.go", "api_level.go", "builder.go", + "bp2build.go", "cc.go", "ccdeps.go", "check.go", diff --git a/cc/bp2build.go b/cc/bp2build.go new file mode 100644 index 000000000..2a590eb84 --- /dev/null +++ b/cc/bp2build.go @@ -0,0 +1,106 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cc + +import ( + "android/soong/android" + "android/soong/bazel" +) + +// bp2build functions and helpers for converting cc_* modules to Bazel. + +func init() { + android.DepsBp2BuildMutators(RegisterDepsBp2Build) +} + +func RegisterDepsBp2Build(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("cc_bp2build_deps", depsBp2BuildMutator) +} + +// A naive deps mutator to add deps on all modules across all combinations of +// target props for cc modules. This is needed to make module -> bazel label +// resolution work in the bp2build mutator later. This is probably +// the wrong way to do it, but it works. +// +// TODO(jingwen): can we create a custom os mutator in depsBp2BuildMutator to do this? +func depsBp2BuildMutator(ctx android.BottomUpMutatorContext) { + module, ok := ctx.Module().(*Module) + if !ok { + // Not a cc module + return + } + + if !module.ConvertWithBp2build(ctx) { + return + } + + var allDeps []string + + for _, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { + // arch specific linker props + if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { + allDeps = append(allDeps, baseLinkerProps.Header_libs...) + allDeps = append(allDeps, baseLinkerProps.Export_header_lib_headers...) + } + } + + ctx.AddDependency(module, nil, android.SortedUniqueStrings(allDeps)...) +} + +// bp2BuildParseHeaderLibs creates a label list attribute containing the header library deps of a module, including +// configurable attribute values. +func bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelListAttribute { + var ret bazel.LabelListAttribute + for _, linkerProps := range module.linker.linkerProps() { + if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { + libs := baseLinkerProps.Header_libs + libs = append(libs, baseLinkerProps.Export_header_lib_headers...) + ret = bazel.MakeLabelListAttribute( + android.BazelLabelForModuleDeps(ctx, android.SortedUniqueStrings(libs))) + break + } + } + + for os, p := range module.GetTargetProperties(&BaseLinkerProperties{}) { + if baseLinkerProps, ok := p.(*BaseLinkerProperties); ok { + libs := baseLinkerProps.Header_libs + libs = append(libs, baseLinkerProps.Export_header_lib_headers...) + libs = android.SortedUniqueStrings(libs) + ret.SetValueForOS(os.Name, android.BazelLabelForModuleDeps(ctx, libs)) + } + } + + return ret +} + +// bp2BuildParseExportedIncludes creates a label list attribute contains the +// exported included directories of a module. +func bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelListAttribute, bazel.LabelListAttribute) { + libraryDecorator := module.linker.(*libraryDecorator) + + includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs + includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...) + + includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs) + + var includeDirGlobs []string + for _, includeDir := range includeDirs { + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h") + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc") + includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp") + } + + headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs) + return bazel.MakeLabelListAttribute(includeDirsLabels), bazel.MakeLabelListAttribute(headersLabels) +} diff --git a/cc/builder.go b/cc/builder.go index 4771b8932..8c9743ff4 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -182,11 +182,11 @@ var ( blueprint.RuleParams{ Depfile: "${out}.d", Deps: blueprint.DepsGCC, - Command: "CROSS_COMPILE=$crossCompile $tocPath $format -i ${in} -o ${out} -d ${out}.d", + Command: "CLANG_BIN=$clangBin $tocPath $format -i ${in} -o ${out} -d ${out}.d", CommandDeps: []string{"$tocPath"}, Restat: true, }, - "crossCompile", "format") + "clangBin", "format") // Rule for invoking clang-tidy (a clang-based linter). clangTidy, clangTidyRE = pctx.RemoteStaticRules("clangTidy", @@ -918,16 +918,12 @@ func transformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Pat outputFile android.WritablePath, flags builderFlags) { var format string - var crossCompile string if ctx.Darwin() { format = "--macho" - crossCompile = "${config.MacToolPath}" } else if ctx.Windows() { format = "--pe" - crossCompile = gccCmd(flags.toolchain, "") } else { format = "--elf" - crossCompile = gccCmd(flags.toolchain, "") } ctx.Build(pctx, android.BuildParams{ @@ -936,8 +932,8 @@ func transformSharedObjectToToc(ctx android.ModuleContext, inputFile android.Pat Output: outputFile, Input: inputFile, Args: map[string]string{ - "crossCompile": crossCompile, - "format": format, + "clangBin": "${config.ClangBin}", + "format": format, }, }) } @@ -1892,8 +1892,8 @@ func (c *Module) deps(ctx DepsContext) Deps { } for _, lib := range deps.ReexportStaticLibHeaders { - if !inList(lib, deps.StaticLibs) { - ctx.PropertyErrorf("export_static_lib_headers", "Static library not in static_libs: '%s'", lib) + if !inList(lib, deps.StaticLibs) && !inList(lib, deps.WholeStaticLibs) { + ctx.PropertyErrorf("export_static_lib_headers", "Static library not in static_libs or whole_static_libs: '%s'", lib) } } @@ -3284,6 +3284,10 @@ func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, type Defaults struct { android.ModuleBase android.DefaultsModuleBase + // Included to support setting bazel_module.label for multiple Soong modules to the same Bazel + // target. This is primarily useful for modules that were architecture specific and instead are + // handled in Bazel as a select(). + android.BazelModuleBase android.ApexModuleBase } @@ -3330,6 +3334,8 @@ func DefaultsFactory(props ...interface{}) android.Module { &RustBindgenClangProperties{}, ) + // Bazel module must be initialized _before_ Defaults to be included in cc_defaults module. + android.InitBazelModule(module) android.InitDefaultsModule(module) return module diff --git a/cc/cc_test.go b/cc/cc_test.go index f1efbff0e..675c0203b 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "io/ioutil" "os" "path/filepath" "reflect" @@ -27,33 +26,11 @@ import ( "android/soong/android" ) -var buildDir string - -func setUp() { - var err error - buildDir, err = ioutil.TempDir("", "soong_cc_test") - if err != nil { - panic(err) - } -} - -func tearDown() { - os.RemoveAll(buildDir) -} - func TestMain(m *testing.M) { - run := func() int { - setUp() - defer tearDown() - - return m.Run() - } - - os.Exit(run()) + os.Exit(m.Run()) } -var ccFixtureFactory = android.NewFixtureFactory( - &buildDir, +var prepareForCcTest = android.GroupFixturePreparers( PrepareForTestWithCcIncludeVndk, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.DeviceVndkVersion = StringPtr("current") @@ -62,62 +39,62 @@ var ccFixtureFactory = android.NewFixtureFactory( }), ) -// testCcWithConfig runs tests using the ccFixtureFactory +// testCcWithConfig runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // // deprecated func testCcWithConfig(t *testing.T, config android.Config) *android.TestContext { t.Helper() - result := ccFixtureFactory.RunTestWithConfig(t, config) + result := prepareForCcTest.RunTestWithConfig(t, config) return result.TestContext } -// testCc runs tests using the ccFixtureFactory +// testCc runs tests using the prepareForCcTest // -// Do not add any new usages of this, instead use the ccFixtureFactory directly as it makes it much +// Do not add any new usages of this, instead use the prepareForCcTest directly as it makes it much // easier to customize the test behavior. // // If it is necessary to customize the behavior of an existing test that uses this then please first -// convert the test to using ccFixtureFactory first and then in a following change add the +// convert the test to using prepareForCcTest first and then in a following change add the // appropriate fixture preparers. Keeping the conversion change separate makes it easy to verify // that it did not change the test behavior unexpectedly. // // deprecated func testCc(t *testing.T, bp string) *android.TestContext { t.Helper() - result := ccFixtureFactory.RunTestWithBp(t, bp) + result := prepareForCcTest.RunTestWithBp(t, bp) return result.TestContext } -// testCcNoVndk runs tests using the ccFixtureFactory +// testCcNoVndk runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // // deprecated func testCcNoVndk(t *testing.T, bp string) *android.TestContext { t.Helper() - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.Platform_vndk_version = StringPtr("VER") return testCcWithConfig(t, config) } -// testCcNoProductVndk runs tests using the ccFixtureFactory +// testCcNoProductVndk runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // // deprecated func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext { t.Helper() - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") return testCcWithConfig(t, config) } -// testCcErrorWithConfig runs tests using the ccFixtureFactory +// testCcErrorWithConfig runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // @@ -125,33 +102,33 @@ func testCcNoProductVndk(t *testing.T, bp string) *android.TestContext { func testCcErrorWithConfig(t *testing.T, pattern string, config android.Config) { t.Helper() - ccFixtureFactory.Extend(). + prepareForCcTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). RunTestWithConfig(t, config) } -// testCcError runs tests using the ccFixtureFactory +// testCcError runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // // deprecated func testCcError(t *testing.T, pattern string, bp string) { t.Helper() - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") testCcErrorWithConfig(t, pattern, config) return } -// testCcErrorProductVndk runs tests using the ccFixtureFactory +// testCcErrorProductVndk runs tests using the prepareForCcTest // // See testCc for an explanation as to how to stop using this deprecated method. // // deprecated func testCcErrorProductVndk(t *testing.T, pattern string, bp string) { t.Helper() - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.ProductVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") @@ -189,7 +166,10 @@ func TestFuchsiaDeps(t *testing.T) { }, }` - result := ccFixtureFactory.Extend(PrepareForTestOnFuchsia).RunTestWithBp(t, bp) + result := android.GroupFixturePreparers( + prepareForCcTest, + PrepareForTestOnFuchsia, + ).RunTestWithBp(t, bp) rt := false fb := false @@ -225,7 +205,10 @@ func TestFuchsiaTargetDecl(t *testing.T) { }, }` - result := ccFixtureFactory.Extend(PrepareForTestOnFuchsia).RunTestWithBp(t, bp) + result := android.GroupFixturePreparers( + prepareForCcTest, + PrepareForTestOnFuchsia, + ).RunTestWithBp(t, bp) ld := result.ModuleForTests("libTest", "fuchsia_arm64_shared").Rule("ld") var objs []string for _, o := range ld.Inputs { @@ -301,13 +284,9 @@ func checkVndkModule(t *testing.T, ctx *android.TestContext, name, subDir string func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) { t.Helper() - mod, ok := ctx.ModuleForTests(moduleName, variant).Module().(android.OutputFileProducer) - if !ok { - t.Errorf("%q must have output\n", moduleName) - return - } - outputFiles, err := mod.OutputFiles("") - if err != nil || len(outputFiles) != 1 { + mod := ctx.ModuleForTests(moduleName, variant) + outputFiles := mod.OutputFiles(t, "") + if len(outputFiles) != 1 { t.Errorf("%q must have single output\n", moduleName) return } @@ -333,14 +312,17 @@ func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singlet } func checkSnapshot(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + t.Helper() checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, false) } func checkSnapshotExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + t.Helper() checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, false, false) } func checkSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string) { + t.Helper() checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true) } @@ -471,7 +453,7 @@ func TestVndk(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.ProductVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") @@ -492,7 +474,7 @@ func TestVndk(t *testing.T) { // Check VNDK snapshot output. snapshotDir := "vndk-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") vndkLibPath := filepath.Join(snapshotVariantPath, fmt.Sprintf("arch-%s-%s", "arm64", "armv8-a")) @@ -593,7 +575,7 @@ func TestVndkLibrariesTxtAndroidMk(t *testing.T) { name: "llndk.libraries.txt", insert_vndk_version: true, }` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := testCcWithConfig(t, config) @@ -643,7 +625,7 @@ func TestVndkUsingCoreVariant(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) @@ -670,7 +652,7 @@ func TestDataLibs(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) @@ -721,7 +703,7 @@ func TestDataLibsRelativeInstallPath(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) @@ -1346,7 +1328,7 @@ func TestVndkExt(t *testing.T) { nocrt: true, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.ProductVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") @@ -1791,7 +1773,7 @@ func TestProductVndkExtDependency(t *testing.T) { nocrt: true, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.ProductVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") @@ -2118,7 +2100,7 @@ func TestEnforceProductVndkVersion(t *testing.T) { } ` - ctx := ccFixtureFactory.RunTestWithBp(t, bp).TestContext + ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext checkVndkModule(t, ctx, "libvndk", "", false, "", productVariant) checkVndkModule(t, ctx, "libvndk_sp", "", true, "", productVariant) @@ -2346,7 +2328,7 @@ func TestMakeLinkType(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") // native:vndk @@ -2552,7 +2534,7 @@ func parseModuleDeps(text string) (modulesInOrder []android.Path, allDeps map[an func getOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) { for _, moduleName := range moduleNames { module := ctx.ModuleForTests(moduleName, variant).Module().(*Module) - output := module.outputFile.Path() + output := module.outputFile.Path().RelativeToTop() paths = append(paths, output) } return paths @@ -2583,7 +2565,8 @@ func TestStaticLibDepReordering(t *testing.T) { variant := "android_arm64_armv8-a_static" moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) - actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).TransitiveStaticLibrariesForOrdering.ToList() + actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo). + TransitiveStaticLibrariesForOrdering.ToList().RelativeToTop() expected := getOutputPaths(ctx, variant, []string{"a", "c", "b", "d"}) if !reflect.DeepEqual(actual, expected) { @@ -2617,7 +2600,8 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) { variant := "android_arm64_armv8-a_static" moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) - actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo).TransitiveStaticLibrariesForOrdering.ToList() + actual := ctx.ModuleProvider(moduleA, StaticLibraryInfoProvider).(StaticLibraryInfo). + TransitiveStaticLibrariesForOrdering.ToList().RelativeToTop() expected := getOutputPaths(ctx, variant, []string{"a", "c", "b"}) if !reflect.DeepEqual(actual, expected) { @@ -2688,9 +2672,11 @@ func TestLlndkLibrary(t *testing.T) { expected := []string{ "android_vendor.VER_arm64_armv8-a_shared_1", "android_vendor.VER_arm64_armv8-a_shared_2", + "android_vendor.VER_arm64_armv8-a_shared_current", "android_vendor.VER_arm64_armv8-a_shared", "android_vendor.VER_arm_armv7-a-neon_shared_1", "android_vendor.VER_arm_armv7-a-neon_shared_2", + "android_vendor.VER_arm_armv7-a-neon_shared_current", "android_vendor.VER_arm_armv7-a-neon_shared", } checkEquals(t, "variants for llndk stubs", expected, actual) @@ -3136,7 +3122,7 @@ func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") config.TestProductVariables.VndkUseCoreVariant = BoolPtr(true) @@ -3190,10 +3176,12 @@ func TestVersionedStubs(t *testing.T) { "android_arm64_armv8-a_shared_1", "android_arm64_armv8-a_shared_2", "android_arm64_armv8-a_shared_3", + "android_arm64_armv8-a_shared_current", "android_arm_armv7-a-neon_shared", "android_arm_armv7-a-neon_shared_1", "android_arm_armv7-a-neon_shared_2", "android_arm_armv7-a-neon_shared_3", + "android_arm_armv7-a-neon_shared_current", } variantsMismatch := false if len(variants) != len(expectedVariants) { @@ -3380,6 +3368,9 @@ func TestDefaults(t *testing.T) { shared: { srcs: ["baz.c"], }, + bazel_module: { + bp2build_available: true, + }, } cc_library_static { @@ -3452,7 +3443,8 @@ func TestProductVariableDefaults(t *testing.T) { } ` - result := ccFixtureFactory.Extend( + result := android.GroupFixturePreparers( + prepareForCcTest, android.PrepareForTestWithVariables, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -3479,7 +3471,8 @@ func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) { } ` - result := ccFixtureFactory.Extend( + result := android.GroupFixturePreparers( + prepareForCcTest, android.PrepareForTestWithAllowMissingDependencies, ).RunTestWithBp(t, bp) @@ -3531,7 +3524,7 @@ func TestInstallSharedLibs(t *testing.T) { } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) hostBin := ctx.ModuleForTests("bin", config.BuildOSTarget.String()).Description("install") @@ -3822,7 +3815,10 @@ var prepareForTestWithMemtagHeap = android.GroupFixturePreparers( func TestSanitizeMemtagHeap(t *testing.T) { variant := "android_arm64_armv8-a" - result := ccFixtureFactory.Extend(prepareForTestWithMemtagHeap).RunTest(t) + result := android.GroupFixturePreparers( + prepareForCcTest, + prepareForTestWithMemtagHeap, + ).RunTest(t) ctx := result.TestContext checkHasMemtagNote(t, ctx.ModuleForTests("default_test", variant), Sync) @@ -3877,7 +3873,8 @@ func TestSanitizeMemtagHeap(t *testing.T) { func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { variant := "android_arm64_armv8-a" - result := ccFixtureFactory.Extend( + result := android.GroupFixturePreparers( + prepareForCcTest, prepareForTestWithMemtagHeap, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.SanitizeDevice = []string{"memtag_heap"} @@ -3937,7 +3934,8 @@ func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { variant := "android_arm64_armv8-a" - result := ccFixtureFactory.Extend( + result := android.GroupFixturePreparers( + prepareForCcTest, prepareForTestWithMemtagHeap, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.SanitizeDevice = []string{"memtag_heap"} diff --git a/cc/gen_test.go b/cc/gen_test.go index 41ef95c27..40a571619 100644 --- a/cc/gen_test.go +++ b/cc/gen_test.go @@ -36,8 +36,10 @@ func TestGen(t *testing.T) { aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("aidl") libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) - if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.Local.CommonFlags) { - t.Errorf("missing aidl includes in global flags") + expected := "-I" + filepath.Dir(aidl.Output.String()) + actual := android.StringsRelativeToTop(ctx.Config(), libfoo.flags.Local.CommonFlags) + if !inList(expected, actual) { + t.Errorf("missing aidl includes in global flags, expected %q, actual %q", expected, actual) } }) @@ -61,7 +63,7 @@ func TestGen(t *testing.T) { aidlManifest := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Output("aidl.sbox.textproto") libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) - if !inList("-I"+filepath.Dir(aidl.Output.String()), libfoo.flags.Local.CommonFlags) { + if !inList("-I"+filepath.Dir(aidl.Output.String()), android.StringsRelativeToTop(ctx.Config(), libfoo.flags.Local.CommonFlags)) { t.Errorf("missing aidl includes in global flags") } diff --git a/cc/genrule_test.go b/cc/genrule_test.go index fa0c6f209..45b343b5a 100644 --- a/cc/genrule_test.go +++ b/cc/genrule_test.go @@ -52,7 +52,7 @@ func TestArchGenruleCmd(t *testing.T) { }, } ` - config := android.TestArchConfig(buildDir, nil, bp, fs) + config := android.TestArchConfig(t.TempDir(), nil, bp, fs) ctx := testGenruleContext(config) diff --git a/cc/library.go b/cc/library.go index 9bec974d3..50fff7f9d 100644 --- a/cc/library.go +++ b/cc/library.go @@ -65,7 +65,8 @@ type LibraryProperties struct { // symbols that are exported for stubs variant of this library. Symbol_file *string `android:"path"` - // List versions to generate stubs libs for. + // List versions to generate stubs libs for. The version name "current" is always + // implicitly added. Versions []string } @@ -171,6 +172,8 @@ type LibraryMutatedProperties struct { // This variant is a stubs lib BuildStubs bool `blueprint:"mutated"` + // This variant is the latest version + IsLatestVersion bool `blueprint:"mutated"` // Version of the stubs lib StubsVersion string `blueprint:"mutated"` // List of all stubs versions associated with an implementation lib @@ -504,12 +507,11 @@ func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext) return } isLibcxx := strings.HasPrefix(dir, "external/libcxx/include") - j := 0 - for i, header := range glob { + for _, header := range glob { if isLibcxx { // Glob all files under this special directory, because of C++ headers with no // extension. - if !strings.HasSuffix(header, "/") { + if strings.HasSuffix(header, "/") { continue } } else { @@ -525,12 +527,8 @@ func (l *libraryDecorator) collectHeadersForSnapshot(ctx android.ModuleContext) continue } } - if i != j { - glob[j] = glob[i] - } - j++ + ret = append(ret, android.PathForSource(ctx, header)) } - glob = glob[:j] } // Collect generated headers @@ -780,7 +778,7 @@ type libraryInterface interface { type versionedInterface interface { buildStubs() bool - setBuildStubs() + setBuildStubs(isLatest bool) hasStubsVariants() bool setStubsVersion(string) stubsVersion() string @@ -1498,7 +1496,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { if ctx.isVndk() && !ctx.IsVndkExt() { return } - } else if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.directlyInAnyApex() { + } else if library.hasStubsVariants() && !ctx.Host() && ctx.directlyInAnyApex() { // Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory. // The original path becomes a symlink to the corresponding file in the // runtime APEX. @@ -1614,11 +1612,29 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin } func (library *libraryDecorator) hasStubsVariants() bool { - return len(library.Properties.Stubs.Versions) > 0 + // Just having stubs.symbol_file is enough to create a stub variant. In that case + // the stub for the future API level is created. + return library.Properties.Stubs.Symbol_file != nil || + len(library.Properties.Stubs.Versions) > 0 } func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) []string { - return library.Properties.Stubs.Versions + if !library.hasStubsVariants() { + return nil + } + + // Future API level is implicitly added if there isn't + vers := library.Properties.Stubs.Versions + if inList(android.FutureApiLevel.String(), vers) { + return vers + } + // In some cases, people use the raw value "10000" in the versions property. + // We shouldn't add the future API level in that case, otherwise there will + // be two identical versions. + if inList(strconv.Itoa(android.FutureApiLevel.FinalOrFutureInt()), vers) { + return vers + } + return append(vers, android.FutureApiLevel.String()) } func (library *libraryDecorator) setStubsVersion(version string) { @@ -1629,8 +1645,9 @@ func (library *libraryDecorator) stubsVersion() string { return library.MutatedProperties.StubsVersion } -func (library *libraryDecorator) setBuildStubs() { +func (library *libraryDecorator) setBuildStubs(isLatest bool) { library.MutatedProperties.BuildStubs = true + library.MutatedProperties.IsLatestVersion = isLatest } func (library *libraryDecorator) setAllStubsVersions(versions []string) { @@ -1642,8 +1659,7 @@ func (library *libraryDecorator) allStubsVersions() []string { } func (library *libraryDecorator) isLatestStubVersion() bool { - versions := library.Properties.Stubs.Versions - return versions[len(versions)-1] == library.stubsVersion() + return library.MutatedProperties.IsLatestVersion } func (library *libraryDecorator) availableFor(what string) bool { @@ -1886,7 +1902,8 @@ func createVersionVariations(mctx android.BottomUpMutatorContext, versions []str c.stl = nil c.Properties.PreventInstall = true lib := moduleLibraryInterface(m) - lib.setBuildStubs() + isLatest := i == (len(versions) - 1) + lib.setBuildStubs(isLatest) if variants[i] != "" { // A non-LLNDK stubs module is hidden from make and has a dependency from the @@ -2029,47 +2046,13 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu return outputFile } -func Bp2BuildParseHeaderLibs(ctx android.TopDownMutatorContext, module *Module) bazel.LabelList { - var headerLibs []string - for _, linkerProps := range module.linker.linkerProps() { - if baseLinkerProps, ok := linkerProps.(*BaseLinkerProperties); ok { - headerLibs = baseLinkerProps.Header_libs - // FIXME: re-export include dirs from baseLinkerProps.Export_header_lib_headers? - break - } - } - - headerLibsLabels := android.BazelLabelForModuleDeps(ctx, headerLibs) - return headerLibsLabels -} - -func Bp2BuildParseExportedIncludes(ctx android.TopDownMutatorContext, module *Module) (bazel.LabelList, bazel.LabelList) { - libraryDecorator := module.linker.(*libraryDecorator) - - includeDirs := libraryDecorator.flagExporter.Properties.Export_system_include_dirs - includeDirs = append(includeDirs, libraryDecorator.flagExporter.Properties.Export_include_dirs...) - - includeDirsLabels := android.BazelLabelForModuleSrc(ctx, includeDirs) - - var includeDirGlobs []string - for _, includeDir := range includeDirs { - includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.h") - includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.inc") - includeDirGlobs = append(includeDirGlobs, includeDir+"/**/*.hpp") - } - - headersLabels := android.BazelLabelForModuleSrc(ctx, includeDirGlobs) - - return includeDirsLabels, headersLabels -} - type bazelCcLibraryStaticAttributes struct { Copts []string - Srcs bazel.LabelList - Deps bazel.LabelList + Srcs bazel.LabelListAttribute + Deps bazel.LabelListAttribute Linkstatic bool - Includes bazel.LabelList - Hdrs bazel.LabelList + Includes bazel.LabelListAttribute + Hdrs bazel.LabelListAttribute } type bazelCcLibraryStatic struct { @@ -2110,7 +2093,7 @@ func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) { break } } - srcsLabels := android.BazelLabelForModuleSrc(ctx, srcs) + srcsLabels := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, srcs)) var staticLibs []string var wholeStaticLibs []string @@ -2134,19 +2117,19 @@ func CcLibraryStaticBp2Build(ctx android.TopDownMutatorContext) { allIncludes = append(allIncludes, localIncludeDirs...) includesLabels := android.BazelLabelForModuleSrc(ctx, allIncludes) - exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module) - includesLabels.Append(exportedIncludesLabels) + exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module) + includesLabels.Append(exportedIncludesLabels.Value) - headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module) - depsLabels.Append(headerLibsLabels) + headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module) + depsLabels.Append(headerLibsLabels.Value) attrs := &bazelCcLibraryStaticAttributes{ Copts: copts, - Srcs: bazel.UniqueBazelLabelList(srcsLabels), - Deps: bazel.UniqueBazelLabelList(depsLabels), + Srcs: srcsLabels, + Deps: bazel.MakeLabelListAttribute(depsLabels), Linkstatic: true, - Includes: bazel.UniqueBazelLabelList(includesLabels), - Hdrs: bazel.UniqueBazelLabelList(exportedIncludesHeadersLabels), + Includes: bazel.MakeLabelListAttribute(includesLabels), + Hdrs: exportedIncludesHeadersLabels, } props := bazel.BazelTargetModuleProperties{ diff --git a/cc/library_headers.go b/cc/library_headers.go index 719d5383c..c8dd2c26e 100644 --- a/cc/library_headers.go +++ b/cc/library_headers.go @@ -62,9 +62,9 @@ func prebuiltLibraryHeaderFactory() android.Module { } type bazelCcLibraryHeadersAttributes struct { - Hdrs bazel.LabelList - Includes bazel.LabelList - Deps bazel.LabelList + Hdrs bazel.LabelListAttribute + Includes bazel.LabelListAttribute + Deps bazel.LabelListAttribute } type bazelCcLibraryHeaders struct { @@ -94,9 +94,9 @@ func CcLibraryHeadersBp2Build(ctx android.TopDownMutatorContext) { return } - exportedIncludesLabels, exportedIncludesHeadersLabels := Bp2BuildParseExportedIncludes(ctx, module) + exportedIncludesLabels, exportedIncludesHeadersLabels := bp2BuildParseExportedIncludes(ctx, module) - headerLibsLabels := Bp2BuildParseHeaderLibs(ctx, module) + headerLibsLabels := bp2BuildParseHeaderLibs(ctx, module) attrs := &bazelCcLibraryHeadersAttributes{ Includes: exportedIncludesLabels, diff --git a/cc/library_test.go b/cc/library_test.go index 49838b48e..797527547 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -199,7 +199,7 @@ func TestStubsVersions(t *testing.T) { }, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.Platform_version_active_codenames = []string{"R"} ctx := testCcWithConfig(t, config) @@ -222,7 +222,7 @@ func TestStubsVersions_NotSorted(t *testing.T) { }, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.Platform_version_active_codenames = []string{"R"} testCcErrorWithConfig(t, `"libfoo" .*: versions: not sorted`, config) } diff --git a/cc/linker.go b/cc/linker.go index 6d0d4160b..21281d2ce 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -599,21 +599,20 @@ var ( _ = pctx.SourcePathVariable("genSortedBssSymbolsPath", "build/soong/scripts/gen_sorted_bss_symbols.sh") genSortedBssSymbols = pctx.AndroidStaticRule("gen_sorted_bss_symbols", blueprint.RuleParams{ - Command: "CROSS_COMPILE=$crossCompile $genSortedBssSymbolsPath ${in} ${out}", - CommandDeps: []string{"$genSortedBssSymbolsPath", "${crossCompile}nm"}, + Command: "CLANG_BIN=${clangBin} $genSortedBssSymbolsPath ${in} ${out}", + CommandDeps: []string{"$genSortedBssSymbolsPath", "${clangBin}/llvm-nm"}, }, - "crossCompile") + "clangBin") ) func (linker *baseLinker) sortBssSymbolsBySize(ctx ModuleContext, in android.Path, symbolOrderingFile android.ModuleOutPath, flags builderFlags) string { - crossCompile := gccCmd(flags.toolchain, "") ctx.Build(pctx, android.BuildParams{ Rule: genSortedBssSymbols, Description: "generate bss symbol order " + symbolOrderingFile.Base(), Output: symbolOrderingFile, Input: in, Args: map[string]string{ - "crossCompile": crossCompile, + "clangBin": "${config.ClangBin}", }, }) return "-Wl,--symbol-ordering-file," + symbolOrderingFile.String() diff --git a/cc/object.go b/cc/object.go index 664be8d4b..ea8d7d3ec 100644 --- a/cc/object.go +++ b/cc/object.go @@ -53,8 +53,17 @@ type objectBazelHandler struct { } func (handler *objectBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool { - // TODO(b/181794963): restore mixed builds once cc_object incompatibility resolved - return false + bazelCtx := ctx.Config().BazelContext + objPaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType) + if ok { + if len(objPaths) != 1 { + ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths) + return false + } + + handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0])) + } + return ok } type ObjectLinkerProperties struct { @@ -103,9 +112,10 @@ func ObjectFactory() android.Module { // For bp2build conversion. type bazelObjectAttributes struct { - Srcs bazel.LabelList - Deps bazel.LabelList + Srcs bazel.LabelListAttribute + Deps bazel.LabelListAttribute Copts bazel.StringListAttribute + Asflags []string Local_include_dirs []string } @@ -147,14 +157,17 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { // Set arch-specific configurable attributes var copts bazel.StringListAttribute - var srcs []string - var excludeSrcs []string + var srcs bazel.LabelListAttribute var localIncludeDirs []string + var asFlags []string for _, props := range m.compiler.compilerProps() { if baseCompilerProps, ok := props.(*BaseCompilerProperties); ok { copts.Value = baseCompilerProps.Cflags - srcs = baseCompilerProps.Srcs - excludeSrcs = baseCompilerProps.Exclude_srcs + srcs = bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrcExcludes( + ctx, + baseCompilerProps.Srcs, + baseCompilerProps.Exclude_srcs)) localIncludeDirs = baseCompilerProps.Local_include_dirs break } @@ -164,24 +177,43 @@ func ObjectBp2Build(ctx android.TopDownMutatorContext) { localIncludeDirs = append(localIncludeDirs, ".") } - var deps bazel.LabelList + var deps bazel.LabelListAttribute for _, props := range m.linker.linkerProps() { if objectLinkerProps, ok := props.(*ObjectLinkerProperties); ok { - deps = android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs) + deps = bazel.MakeLabelListAttribute( + android.BazelLabelForModuleDeps(ctx, objectLinkerProps.Objs)) + } + } + + productVariableProps := android.ProductVariableProperties(ctx) + if props, exists := productVariableProps["Asflags"]; exists { + // TODO(b/183595873): consider deduplicating handling of product variable properties + for _, prop := range props { + flags, ok := prop.Property.([]string) + if !ok { + ctx.ModuleErrorf("Could not convert product variable asflag property") + return + } + // TODO(b/183595873) handle other product variable usages -- as selects? + if newFlags, subbed := bazel.TryVariableSubstitutions(flags, prop.ProductConfigVariable); subbed { + asFlags = append(asFlags, newFlags...) + } } } + // TODO(b/183595872) warn/error if we're not handling product variables for arch, p := range m.GetArchProperties(&BaseCompilerProperties{}) { if cProps, ok := p.(*BaseCompilerProperties); ok { + srcs.SetValueForArch(arch.Name, android.BazelLabelForModuleSrcExcludes(ctx, cProps.Srcs, cProps.Exclude_srcs)) copts.SetValueForArch(arch.Name, cProps.Cflags) } } - copts.SetValueForArch("default", []string{}) attrs := &bazelObjectAttributes{ - Srcs: android.BazelLabelForModuleSrcExcludes(ctx, srcs, excludeSrcs), + Srcs: srcs, Deps: deps, Copts: copts, + Asflags: asFlags, Local_include_dirs: localIncludeDirs, } diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index 20274b2ba..fa6dd87eb 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -15,7 +15,6 @@ package cc import ( - "path/filepath" "testing" "android/soong/android" @@ -23,14 +22,17 @@ import ( "github.com/google/blueprint" ) -var prebuiltFixtureFactory = ccFixtureFactory.Extend( +var prepareForPrebuiltTest = android.GroupFixturePreparers( + prepareForCcTest, android.PrepareForTestWithAndroidMk, ) func testPrebuilt(t *testing.T, bp string, fs android.MockFS, handlers ...android.FixturePreparer) *android.TestContext { - result := prebuiltFixtureFactory.Extend( + result := android.GroupFixturePreparers( + prepareForPrebuiltTest, fs.AddToFixture(), - ).Extend(handlers...).RunTestWithBp(t, bp) + android.GroupFixturePreparers(handlers...), + ).RunTestWithBp(t, bp) return result.TestContext } @@ -302,8 +304,7 @@ func TestPrebuiltSymlinkedHostBinary(t *testing.T) { }) fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") - assertString(t, fooRule.Output.String(), - filepath.Join(buildDir, ".intermediates/foo/linux_glibc_x86_64/foo")) + assertString(t, fooRule.Output.String(), "out/soong/.intermediates/foo/linux_glibc_x86_64/foo") assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") var libfooDep android.Path @@ -313,8 +314,7 @@ func TestPrebuiltSymlinkedHostBinary(t *testing.T) { break } } - assertString(t, libfooDep.String(), - filepath.Join(buildDir, ".intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so")) + assertString(t, libfooDep.String(), "out/soong/.intermediates/libfoo/linux_glibc_x86_64_shared/libfoo.so") } func TestPrebuiltLibrarySanitized(t *testing.T) { diff --git a/cc/proto_test.go b/cc/proto_test.go index f8bbd2643..b9c89c744 100644 --- a/cc/proto_test.go +++ b/cc/proto_test.go @@ -61,7 +61,7 @@ func TestProto(t *testing.T) { t.Errorf("expected %q in %q", w, cmd) } - foobarPath := foobar.Module().(android.HostToolProvider).HostToolPath().String() + foobarPath := foobar.Module().(android.HostToolProvider).HostToolPath().RelativeToTop().String() if w := "--plugin=protoc-gen-foobar=" + foobarPath; !strings.Contains(cmd, w) { t.Errorf("expected %q in %q", w, cmd) diff --git a/cc/sdk_test.go b/cc/sdk_test.go index 5a3c181dc..61925e30c 100644 --- a/cc/sdk_test.go +++ b/cc/sdk_test.go @@ -66,6 +66,7 @@ func TestSdkMutator(t *testing.T) { } else { toFile = m.outputFile.Path() } + toFile = toFile.RelativeToTop() rule := from.Description("link") for _, dep := range rule.Implicits { @@ -188,12 +188,7 @@ func (stl *stl) deps(ctx BaseModuleContext, deps Deps) Deps { if needsLibAndroidSupport(ctx) { deps.StaticLibs = append(deps.StaticLibs, "ndk_libandroid_support") } - // TODO: Switch the NDK over to the LLVM unwinder for non-arm32 architectures. - if ctx.Arch().ArchType == android.Arm { - deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind") - } else { - deps.StaticLibs = append(deps.StaticLibs, "libgcc_stripped") - } + deps.StaticLibs = append(deps.StaticLibs, "ndk_libunwind") default: panic(fmt.Errorf("Unknown stl: %q", stl.Properties.SelectedStl)) } diff --git a/cc/vendor_snapshot_test.go b/cc/vendor_snapshot_test.go index 083327740..8d13cebe6 100644 --- a/cc/vendor_snapshot_test.go +++ b/cc/vendor_snapshot_test.go @@ -86,7 +86,7 @@ func TestVendorSnapshotCapture(t *testing.T) { symbol_file: "", } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := testCcWithConfig(t, config) @@ -94,7 +94,7 @@ func TestVendorSnapshotCapture(t *testing.T) { // Check Vendor snapshot output. snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var jsonFiles []string @@ -212,7 +212,7 @@ func TestVendorSnapshotDirected(t *testing.T) { nocrt: true, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") config.TestProductVariables.DirectedVendorSnapshot = true @@ -224,7 +224,7 @@ func TestVendorSnapshotDirected(t *testing.T) { // Check Vendor snapshot output. snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var includeJsonFiles []string @@ -516,7 +516,7 @@ func TestVendorSnapshotUse(t *testing.T) { "vndk/libvndk.so": nil, } - config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := CreateTestContext(config) @@ -628,7 +628,7 @@ func TestVendorSnapshotSanitizer(t *testing.T) { }, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("BOARD") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := testCcWithConfig(t, config) @@ -707,7 +707,7 @@ func TestVendorSnapshotExclude(t *testing.T) { "device/vendor.cpp": nil, } - config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := CreateTestContext(config) @@ -730,7 +730,7 @@ func TestVendorSnapshotExclude(t *testing.T) { // Verify the content of the vendor snapshot. snapshotDir := "vendor-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("vendor-snapshot") var includeJsonFiles []string @@ -799,7 +799,7 @@ func TestVendorSnapshotExcludeInVendorProprietaryPathErrors(t *testing.T) { "device/vendor.cpp": nil, } - config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := CreateTestContext(config) @@ -873,7 +873,7 @@ func TestRecoverySnapshotCapture(t *testing.T) { recovery_available: true, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := testCcWithConfig(t, config) @@ -881,7 +881,7 @@ func TestRecoverySnapshotCapture(t *testing.T) { // Check Recovery snapshot output. snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var jsonFiles []string @@ -991,7 +991,7 @@ func TestRecoverySnapshotExclude(t *testing.T) { "device/recovery.cpp": nil, } - config := TestConfig(buildDir, android.Android, nil, "", mockFS) + config := TestConfig(t.TempDir(), android.Android, nil, "", mockFS) config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") ctx := CreateTestContext(config) @@ -1014,7 +1014,7 @@ func TestRecoverySnapshotExclude(t *testing.T) { // Verify the content of the recovery snapshot. snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var includeJsonFiles []string @@ -1091,7 +1091,7 @@ func TestRecoverySnapshotDirected(t *testing.T) { nocrt: true, } ` - config := TestConfig(buildDir, android.Android, nil, bp, nil) + config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) config.TestProductVariables.DeviceVndkVersion = StringPtr("current") config.TestProductVariables.RecoverySnapshotVersion = StringPtr("current") config.TestProductVariables.Platform_vndk_version = StringPtr("VER") @@ -1104,7 +1104,7 @@ func TestRecoverySnapshotDirected(t *testing.T) { // Check recovery snapshot output. snapshotDir := "recovery-snapshot" - snapshotVariantPath := filepath.Join(buildDir, snapshotDir, "arm64") + snapshotVariantPath := filepath.Join("out/soong", snapshotDir, "arm64") snapshotSingleton := ctx.SingletonForTests("recovery-snapshot") var includeJsonFiles []string diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go index fcc80a94e..7bd086882 100644 --- a/cmd/sbox/sbox.go +++ b/cmd/sbox/sbox.go @@ -387,6 +387,14 @@ func copyOneFile(from string, to string, executable bool) error { } defer in.Close() + // Remove the target before copying. In most cases the file won't exist, but if there are + // duplicate copy rules for a file and the source file was read-only the second copy could + // fail. + err = os.Remove(to) + if err != nil && !os.IsNotExist(err) { + return err + } + out, err := os.Create(to) if err != nil { return err diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index e2fc78cef..3abf9783e 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -24,7 +24,6 @@ import ( "time" "android/soong/shared" - "github.com/google/blueprint/bootstrap" "android/soong/android" @@ -65,16 +64,10 @@ func newNameResolver(config android.Config) *android.NameResolver { return android.NewNameResolver(exportFilter) } -// bazelConversionRequested checks that the user is intending to convert -// Blueprint to Bazel BUILD files. -func bazelConversionRequested(configuration android.Config) bool { - return configuration.IsEnvTrue("GENERATE_BAZEL_FILES") -} - -func newContext(configuration android.Config) *android.Context { +func newContext(configuration android.Config, prepareBuildActions bool) *android.Context { ctx := android.NewContext(configuration) ctx.Register() - if !shouldPrepareBuildActions(configuration) { + if !prepareBuildActions { configuration.SetStopBefore(bootstrap.StopBeforePrepareBuildActions) } ctx.SetNameInterface(newNameResolver(configuration)) @@ -91,6 +84,84 @@ func newConfig(srcDir string) android.Config { return configuration } +// Bazel-enabled mode. Soong runs in two passes. +// First pass: Analyze the build tree, but only store all bazel commands +// needed to correctly evaluate the tree in the second pass. +// TODO(cparsons): Don't output any ninja file, as the second pass will overwrite +// the incorrect results from the first pass, and file I/O is expensive. +func runMixedModeBuild(configuration android.Config, firstCtx *android.Context, extraNinjaDeps []string) { + configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja) + bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...) + // Invoke bazel commands and save results for second pass. + if err := configuration.BazelContext.InvokeBazel(); err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } + // Second pass: Full analysis, using the bazel command results. Output ninja file. + secondPassConfig, err := android.ConfigForAdditionalRun(configuration) + if err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } + secondCtx := newContext(secondPassConfig, true) + bootstrap.Main(secondCtx.Context, secondPassConfig, false, extraNinjaDeps...) +} + +// Run the code-generation phase to convert BazelTargetModules to BUILD files. +func runQueryView(configuration android.Config, ctx *android.Context) { + codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView) + absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir) + if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } +} + +func runSoongDocs(configuration android.Config, extraNinjaDeps []string) { + ctx := newContext(configuration, false) + bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...) + if err := writeDocs(ctx, configuration, docFile); err != nil { + fmt.Fprintf(os.Stderr, "%s", err) + os.Exit(1) + } +} + +func writeMetrics(configuration android.Config) { + metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb") + err := android.WriteMetrics(configuration, metricsFile) + if err != nil { + fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err) + os.Exit(1) + } +} + +func doChosenActivity(configuration android.Config, extraNinjaDeps []string) { + bazelConversionRequested := configuration.IsEnvTrue("GENERATE_BAZEL_FILES") + mixedModeBuild := configuration.BazelContext.BazelEnabled() + generateQueryView := bazelQueryViewDir != "" + + if bazelConversionRequested { + // Run the alternate pipeline of bp2build mutators and singleton to convert + // Blueprint to BUILD files before everything else. + runBp2Build(configuration, extraNinjaDeps) + return + } + + ctx := newContext(configuration, !generateQueryView) + if mixedModeBuild { + runMixedModeBuild(configuration, ctx, extraNinjaDeps) + } else { + bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...) + } + + // Convert the Soong module graph into Bazel BUILD files. + if generateQueryView { + runQueryView(configuration, ctx) + return + } + writeMetrics(configuration) +} + func main() { flag.Parse() @@ -101,7 +172,6 @@ func main() { usedVariablesFile := shared.JoinPath(outDir, "soong.environment.used") // The top-level Blueprints file is passed as the first argument. srcDir := filepath.Dir(flag.Arg(0)) - var ctx *android.Context configuration := newConfig(srcDir) extraNinjaDeps := []string{ configuration.ProductVariablesFileName, @@ -122,72 +192,17 @@ func main() { extraNinjaDeps = append(extraNinjaDeps, filepath.Join(configuration.BuildDir(), "always_rerun_for_delve")) } - bazelConversionRequested := bazelConversionRequested(configuration) - if bazelConversionRequested { - // Run the alternate pipeline of bp2build mutators and singleton to convert Blueprint to BUILD files - // before everything else. - runBp2Build(srcDir, configuration, extraNinjaDeps) - } else if configuration.BazelContext.BazelEnabled() { - // Bazel-enabled mode. Soong runs in two passes. - // First pass: Analyze the build tree, but only store all bazel commands - // needed to correctly evaluate the tree in the second pass. - // TODO(cparsons): Don't output any ninja file, as the second pass will overwrite - // the incorrect results from the first pass, and file I/O is expensive. - firstCtx := newContext(configuration) - configuration.SetStopBefore(bootstrap.StopBeforeWriteNinja) - bootstrap.Main(firstCtx.Context, configuration, false, extraNinjaDeps...) - // Invoke bazel commands and save results for second pass. - if err := configuration.BazelContext.InvokeBazel(); err != nil { - fmt.Fprintf(os.Stderr, "%s", err) - os.Exit(1) - } - // Second pass: Full analysis, using the bazel command results. Output ninja file. - secondPassConfig, err := android.ConfigForAdditionalRun(configuration) - if err != nil { - fmt.Fprintf(os.Stderr, "%s", err) - os.Exit(1) - } - ctx = newContext(secondPassConfig) - bootstrap.Main(ctx.Context, secondPassConfig, false, extraNinjaDeps...) - } else { - ctx = newContext(configuration) - bootstrap.Main(ctx.Context, configuration, false, extraNinjaDeps...) - } - - // Convert the Soong module graph into Bazel BUILD files. - if !bazelConversionRequested && bazelQueryViewDir != "" { - // Run the code-generation phase to convert BazelTargetModules to BUILD files. - codegenContext := bp2build.NewCodegenContext(configuration, *ctx, bp2build.QueryView) - absoluteQueryViewDir := shared.JoinPath(topDir, bazelQueryViewDir) - if err := createBazelQueryView(codegenContext, absoluteQueryViewDir); err != nil { - fmt.Fprintf(os.Stderr, "%s", err) - os.Exit(1) - } - } - - if !bazelConversionRequested && docFile != "" { - if err := writeDocs(ctx, configuration, docFile); err != nil { - fmt.Fprintf(os.Stderr, "%s", err) - os.Exit(1) - } - } - - // TODO(ccross): make this a command line argument. Requires plumbing through blueprint - // to affect the command line of the primary builder. - if !bazelConversionRequested && shouldPrepareBuildActions(configuration) { - metricsFile := filepath.Join(bootstrap.CmdlineBuildDir(), "soong_build_metrics.pb") - err := android.WriteMetrics(configuration, metricsFile) - if err != nil { - fmt.Fprintf(os.Stderr, "error writing soong_build metrics %s: %s", metricsFile, err) - os.Exit(1) - } + if docFile != "" { + // We don't write an used variables file when generating documentation + // because that is done from within the actual builds as a Ninja action and + // thus it would overwrite the actual used variables file so this is + // special-cased. + runSoongDocs(configuration, extraNinjaDeps) + return } - if docFile == "" { - // Let's not overwrite the used variables file when generating - // documentation - writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration) - } + doChosenActivity(configuration, extraNinjaDeps) + writeUsedVariablesFile(shared.JoinPath(topDir, usedVariablesFile), configuration) } func writeUsedVariablesFile(path string, configuration android.Config) { @@ -218,7 +233,7 @@ func writeUsedVariablesFile(path string, configuration android.Config) { // Run Soong in the bp2build mode. This creates a standalone context that registers // an alternate pipeline of mutators and singletons specifically for generating // Bazel BUILD files instead of Ninja files. -func runBp2Build(srcDir string, configuration android.Config, extraNinjaDeps []string) { +func runBp2Build(configuration android.Config, extraNinjaDeps []string) { // Register an alternate set of singletons and mutators for bazel // conversion for Bazel conversion. bp2buildCtx := android.NewContext(configuration) @@ -233,7 +248,7 @@ func runBp2Build(srcDir string, configuration android.Config, extraNinjaDeps []s // configurations or variables, since those will generate different BUILD // files based on how the user has configured their tree. bp2buildCtx.SetModuleListFile(bootstrap.CmdlineModuleListFile()) - modulePaths, err := bp2buildCtx.ListModulePaths(srcDir) + modulePaths, err := bp2buildCtx.ListModulePaths(configuration.SrcDir()) if err != nil { panic(err) } @@ -283,20 +298,3 @@ func runBp2Build(srcDir string, configuration android.Config, extraNinjaDeps []s []byte(fmt.Sprintf("%s: \\\n %s\n", ninjaFileName, extraNinjaDepsString)), 0666) } - -// shouldPrepareBuildActions reads configuration and flags if build actions -// should be generated. -func shouldPrepareBuildActions(configuration android.Config) bool { - // Generating Soong docs - if docFile != "" { - return false - } - - // Generating a directory for Soong query (queryview) - if bazelQueryViewDir != "" { - return false - } - - // Generating a directory for converted Bazel BUILD files - return !bazelConversionRequested(configuration) -} diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go index 20d9622dc..739e609ed 100644 --- a/filesystem/logical_partition.go +++ b/filesystem/logical_partition.go @@ -40,9 +40,14 @@ type logicalPartitionProperties struct { // Set the name of the output. Defaults to <module_name>.img. Stem *string - // Total size of the logical partition + // Total size of the logical partition. If set to "auto", total size is automatically + // calcaulted as minimum. Size *string + // List of partitions for default group. Default group has no size limit and automatically + // minimized when creating an image. + Default_group []partitionProperties + // List of groups. A group defines a fixed sized region. It can host one or more logical // partitions and their total size is limited by the size of the group they are in. Groups []groupProperties @@ -52,7 +57,7 @@ type logicalPartitionProperties struct { } type groupProperties struct { - // Name of the partition group + // Name of the partition group. Can't be "default"; use default_group instead. Name *string // Size of the partition group @@ -92,8 +97,9 @@ func (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext // Sparse the filesystem images and calculate their sizes sparseImages := make(map[string]android.OutputPath) sparseImageSizes := make(map[string]android.OutputPath) - for _, group := range l.properties.Groups { - for _, part := range group.Partitions { + + sparsePartitions := func(partitions []partitionProperties) { + for _, part := range partitions { sparseImg, sizeTxt := sparseFilesystem(ctx, part, builder) pName := proptools.String(part.Name) sparseImages[pName] = sparseImg @@ -101,14 +107,19 @@ func (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext } } + for _, group := range l.properties.Groups { + sparsePartitions(group.Partitions) + } + + sparsePartitions(l.properties.Default_group) + cmd := builder.Command().BuiltTool("lpmake") size := proptools.String(l.properties.Size) if size == "" { ctx.PropertyErrorf("size", "must be set") - } - if _, err := strconv.Atoi(size); err != nil { - ctx.PropertyErrorf("size", "must be a number") + } else if _, err := strconv.Atoi(size); err != nil && size != "auto" { + ctx.PropertyErrorf("size", `must be a number or "auto"`) } cmd.FlagWithArg("--device-size=", size) @@ -123,10 +134,32 @@ func (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext groupNames := make(map[string]bool) partitionNames := make(map[string]bool) + addPartitionsToGroup := func(partitions []partitionProperties, gName string) { + for _, part := range partitions { + pName := proptools.String(part.Name) + if pName == "" { + ctx.PropertyErrorf("groups.partitions.name", "must be set") + } + if _, ok := partitionNames[pName]; ok { + ctx.PropertyErrorf("groups.partitions.name", "already exists") + } else { + partitionNames[pName] = true + } + // Get size of the partition by reading the -size.txt file + pSize := fmt.Sprintf("$(cat %s)", sparseImageSizes[pName]) + cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName)) + cmd.FlagWithInput("--image="+pName+"=", sparseImages[pName]) + } + } + + addPartitionsToGroup(l.properties.Default_group, "default") + for _, group := range l.properties.Groups { gName := proptools.String(group.Name) if gName == "" { ctx.PropertyErrorf("groups.name", "must be set") + } else if gName == "default" { + ctx.PropertyErrorf("groups.name", `can't use "default" as a group name. Use default_group instead`) } if _, ok := groupNames[gName]; ok { ctx.PropertyErrorf("group.name", "already exists") @@ -142,21 +175,7 @@ func (l *logicalPartition) GenerateAndroidBuildActions(ctx android.ModuleContext } cmd.FlagWithArg("--group=", gName+":"+gSize) - for _, part := range group.Partitions { - pName := proptools.String(part.Name) - if pName == "" { - ctx.PropertyErrorf("groups.partitions.name", "must be set") - } - if _, ok := partitionNames[pName]; ok { - ctx.PropertyErrorf("groups.partitions.name", "already exists") - } else { - partitionNames[pName] = true - } - // Get size of the partition by reading the -size.txt file - pSize := fmt.Sprintf("$(cat %s)", sparseImageSizes[pName]) - cmd.FlagWithArg("--partition=", fmt.Sprintf("%s:readonly:%s:%s", pName, pSize, gName)) - cmd.FlagWithInput("--image="+pName+"=", sparseImages[pName]) - } + addPartitionsToGroup(group.Partitions, gName) } l.output = android.PathForModuleOut(ctx, l.installFileName()).OutputPath diff --git a/genrule/genrule.go b/genrule/genrule.go index 9019a839d..5d438eac2 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -798,9 +798,9 @@ type genRuleProperties struct { } type bazelGenruleAttributes struct { - Srcs bazel.LabelList + Srcs bazel.LabelListAttribute Outs []string - Tools bazel.LabelList + Tools bazel.LabelListAttribute Cmd string } @@ -828,15 +828,16 @@ func GenruleBp2Build(ctx android.TopDownMutatorContext) { } // Bazel only has the "tools" attribute. - tools := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) - tool_files := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) - tools.Append(tool_files) + tools_prop := android.BazelLabelForModuleDeps(ctx, m.properties.Tools) + tool_files_prop := android.BazelLabelForModuleSrc(ctx, m.properties.Tool_files) + tools_prop.Append(tool_files_prop) - srcs := android.BazelLabelForModuleSrc(ctx, m.properties.Srcs) + tools := bazel.MakeLabelListAttribute(tools_prop) + srcs := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, m.properties.Srcs)) var allReplacements bazel.LabelList - allReplacements.Append(tools) - allReplacements.Append(srcs) + allReplacements.Append(tools.Value) + allReplacements.Append(srcs.Value) // Replace in and out variables with $< and $@ var cmd string @@ -844,9 +845,9 @@ func GenruleBp2Build(ctx android.TopDownMutatorContext) { cmd = strings.Replace(*m.properties.Cmd, "$(in)", "$(SRCS)", -1) cmd = strings.Replace(cmd, "$(out)", "$(OUTS)", -1) cmd = strings.Replace(cmd, "$(genDir)", "$(GENDIR)", -1) - if len(tools.Includes) > 0 { - cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Includes[0].Label), -1) - cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Includes[0].Label), -1) + if len(tools.Value.Includes) > 0 { + cmd = strings.Replace(cmd, "$(location)", fmt.Sprintf("$(location %s)", tools.Value.Includes[0].Label), -1) + cmd = strings.Replace(cmd, "$(locations)", fmt.Sprintf("$(locations %s)", tools.Value.Includes[0].Label), -1) } for _, l := range allReplacements.Includes { bpLoc := fmt.Sprintf("$(location %s)", l.Bp_text) diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index 2ee456d56..3f1e9f3b9 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -670,7 +670,8 @@ func TestGenruleAllowMissingDependencies(t *testing.T) { cmd: "cat $(in) > $(out)", } ` - result := prepareForGenRuleTest.Extend( + result := android.GroupFixturePreparers( + prepareForGenRuleTest, android.FixtureModifyConfigAndContext( func(config android.Config, ctx *android.TestContext) { config.TestProductVariables.Allow_missing_dependencies = proptools.BoolPtr(true) diff --git a/java/Android.bp b/java/Android.bp index b6c14ac37..8334b85ec 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -50,6 +50,7 @@ bootstrap_go_package { "kotlin.go", "lint.go", "legacy_core_platform_api_usage.go", + "platform_bootclasspath.go", "platform_compat_config.go", "plugin.go", "prebuilt_apis.go", @@ -79,6 +80,7 @@ bootstrap_go_package { "java_test.go", "jdeps_test.go", "kotlin_test.go", + "platform_bootclasspath_test.go", "platform_compat_config_test.go", "plugin_test.go", "rro_test.go", diff --git a/java/aar.go b/java/aar.go index 67b9ef019..a122a94cb 100644 --- a/java/aar.go +++ b/java/aar.go @@ -163,7 +163,7 @@ func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool { a.aaptProperties.RROEnforcedForDependent } -func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, +func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext, manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) { @@ -218,7 +218,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext sdkContext, linkDeps = append(linkDeps, assetDeps...) // SDK version flags - minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -266,7 +266,7 @@ var extractAssetsRule = pctx.AndroidStaticRule("extractAssets", CommandDeps: []string{"${config.Zip2ZipCmd}"}, }) -func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, +func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap, extraLinkFlags ...string) { transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags := @@ -397,7 +397,7 @@ func (a *aapt) buildActions(ctx android.ModuleContext, sdkContext sdkContext, } // aaptLibs collects libraries from dependencies and sdk_version and converts them into paths -func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( +func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap) ( transitiveStaticLibs, transitiveStaticLibManifests android.Paths, staticRRODirs []rroDir, assets, deps android.Paths, flags []string) { var sharedLibs android.Paths @@ -498,7 +498,7 @@ var _ AndroidLibraryDependency = (*AndroidLibrary)(nil) func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { a.Module.deps(ctx) - sdkDep := decodeSdkDep(ctx, sdkContext(a)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) if sdkDep.hasFrameworkLibs() { a.aapt.deps(ctx, sdkDep) } @@ -507,7 +507,7 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.aapt.isLibrary = true a.classLoaderContexts = make(dexpreopt.ClassLoaderContextMap) - a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts) + a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts) a.hideApexVariantFromMake = !ctx.Provider(android.ApexInfoProvider).(android.ApexInfo).IsForPlatform() @@ -625,23 +625,23 @@ func (a *AARImport) OutputFiles(tag string) (android.Paths, error) { } } -func (a *AARImport) sdkVersion() sdkSpec { - return sdkSpecFrom(String(a.properties.Sdk_version)) +func (a *AARImport) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom(String(a.properties.Sdk_version)) } -func (a *AARImport) systemModules() string { +func (a *AARImport) SystemModules() string { return "" } -func (a *AARImport) minSdkVersion() sdkSpec { +func (a *AARImport) MinSdkVersion() android.SdkSpec { if a.properties.Min_sdk_version != nil { - return sdkSpecFrom(*a.properties.Min_sdk_version) + return android.SdkSpecFrom(*a.properties.Min_sdk_version) } - return a.sdkVersion() + return a.SdkVersion() } -func (a *AARImport) targetSdkVersion() sdkSpec { - return a.sdkVersion() +func (a *AARImport) TargetSdkVersion() android.SdkSpec { + return a.SdkVersion() } func (a *AARImport) javaVersion() string { @@ -700,7 +700,7 @@ func (a *AARImport) JacocoReportClassesFile() android.Path { func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { if !ctx.Config().AlwaysUsePrebuiltSdks() { - sdkDep := decodeSdkDep(ctx, sdkContext(a)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) if sdkDep.useModule && sdkDep.frameworkResModule != "" { ctx.AddVariationDependencies(nil, frameworkResTag, sdkDep.frameworkResModule) } @@ -780,7 +780,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { linkDeps = append(linkDeps, a.manifest) transitiveStaticLibs, staticLibManifests, staticRRODirs, transitiveAssets, libDeps, libFlags := - aaptLibs(ctx, sdkContext(a), nil) + aaptLibs(ctx, android.SdkContext(a), nil) _ = staticLibManifests _ = staticRRODirs diff --git a/java/android_manifest.go b/java/android_manifest.go index b30f3d2c8..6b7395baa 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -43,7 +43,7 @@ var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger", "args", "libs") // Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml -func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, +func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext android.SdkContext, classLoaderContexts dexpreopt.ClassLoaderContextMap, isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path { @@ -51,7 +51,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext if isLibrary { args = append(args, "--library") } else { - minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersion(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersion(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } @@ -87,7 +87,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext args = append(args, "--logging-parent", loggingParent) } var deps android.Paths - targetSdkVersion, err := sdkContext.targetSdkVersion().effectiveVersionString(ctx) + targetSdkVersion, err := sdkContext.TargetSdkVersion().EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid targetSdkVersion: %s", err) } @@ -96,7 +96,7 @@ func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext deps = append(deps, ApiFingerprintPath(ctx)) } - minSdkVersion, err := sdkContext.minSdkVersion().effectiveVersionString(ctx) + minSdkVersion, err := sdkContext.MinSdkVersion().EffectiveVersionString(ctx) if err != nil { ctx.ModuleErrorf("invalid minSdkVersion: %s", err) } diff --git a/java/androidmk.go b/java/androidmk.go index 3d3eae530..75661a7a5 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -106,7 +106,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if len(library.dexpreopter.builtInstalled) > 0 { entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", library.dexpreopter.builtInstalled) } - entries.SetString("LOCAL_SDK_VERSION", library.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", library.SdkVersion().Raw) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) @@ -255,7 +255,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags) entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest) - entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw) + entries.SetString("LOCAL_SDK_VERSION", prebuilt.SdkVersion().Raw) }, }, }} diff --git a/java/app.go b/java/app.go index b849b98b1..ec30b4940 100755 --- a/java/app.go +++ b/java/app.go @@ -213,16 +213,16 @@ func (c Certificate) AndroidMkString() string { func (a *AndroidApp) DepsMutator(ctx android.BottomUpMutatorContext) { a.Module.deps(ctx) - if String(a.appProperties.Stl) == "c++_shared" && !a.sdkVersion().specified() { + if String(a.appProperties.Stl) == "c++_shared" && !a.SdkVersion().Specified() { ctx.PropertyErrorf("stl", "sdk_version must be set in order to use c++_shared") } - sdkDep := decodeSdkDep(ctx, sdkContext(a)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) if sdkDep.hasFrameworkLibs() { a.aapt.deps(ctx, sdkDep) } - usesSDK := a.sdkVersion().specified() && a.sdkVersion().kind != sdkCorePlatform + usesSDK := a.SdkVersion().Specified() && a.SdkVersion().Kind != android.SdkCorePlatform if usesSDK && Bool(a.appProperties.Jni_uses_sdk_apis) { ctx.PropertyErrorf("jni_uses_sdk_apis", @@ -279,14 +279,14 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { if a.Updatable() { - if !a.sdkVersion().stable() { - ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.sdkVersion()) + if !a.SdkVersion().Stable() { + ctx.PropertyErrorf("sdk_version", "Updatable apps must use stable SDKs, found %v", a.SdkVersion()) } if String(a.deviceProperties.Min_sdk_version) == "" { ctx.PropertyErrorf("updatable", "updatable apps must set min_sdk_version.") } - if minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx); err == nil { + if minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx); err == nil { a.checkJniLibsSdkVersion(ctx, minSdkVersion) android.CheckMinSdkVersion(a, ctx, minSdkVersion.ApiLevel(ctx)) } else { @@ -304,7 +304,7 @@ func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { // because, sdk_version is overridden by min_sdk_version (if set as smaller) // and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree // will meet the requirements. -func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion sdkVersion) { +func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.SdkVersion) { // It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType() ctx.VisitDirectDeps(func(m android.Module) { if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) { @@ -312,9 +312,9 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer } dep, _ := m.(*cc.Module) // The domain of cc.sdk_version is "current" and <number> - // We can rely on sdkSpec to convert it to <number> so that "current" is handled - // properly regardless of sdk finalization. - jniSdkVersion, err := sdkSpecFrom(dep.SdkVersion()).effectiveVersion(ctx) + // We can rely on android.SdkSpec to convert it to <number> so that "current" is + // handled properly regardless of sdk finalization. + jniSdkVersion, err := android.SdkSpecFrom(dep.SdkVersion()).EffectiveVersion(ctx) if err != nil || minSdkVersion < jniSdkVersion { ctx.OtherModuleErrorf(dep, "sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", dep.SdkVersion(), minSdkVersion, ctx.ModuleName()) @@ -327,9 +327,9 @@ func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVer // Returns true if the native libraries should be stored in the APK uncompressed and the // extractNativeLibs application flag should be set to false in the manifest. func (a *AndroidApp) useEmbeddedNativeLibs(ctx android.ModuleContext) bool { - minSdkVersion, err := a.minSdkVersion().effectiveVersion(ctx) + minSdkVersion, err := a.MinSdkVersion().EffectiveVersion(ctx) if err != nil { - ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.minSdkVersion(), err) + ctx.PropertyErrorf("min_sdk_version", "invalid value %q: %s", a.MinSdkVersion(), err) } apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) @@ -419,7 +419,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { a.aapt.splitNames = a.appProperties.Package_splits a.aapt.LoggingParent = String(a.overridableAppProperties.Logging_parent) - a.aapt.buildActions(ctx, sdkContext(a), a.classLoaderContexts, aaptLinkFlags...) + a.aapt.buildActions(ctx, android.SdkContext(a), a.classLoaderContexts, aaptLinkFlags...) // apps manifests are handled by aapt, don't let Module see them a.properties.Manifest = nil @@ -720,8 +720,8 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } type appDepsInterface interface { - sdkVersion() sdkSpec - minSdkVersion() sdkSpec + SdkVersion() android.SdkSpec + MinSdkVersion() android.SdkSpec RequiresStableAPIs(ctx android.BaseModuleContext) bool } @@ -734,8 +734,8 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, seenModulePaths := make(map[string]bool) if checkNativeSdkVersion { - checkNativeSdkVersion = app.sdkVersion().specified() && - app.sdkVersion().kind != sdkCorePlatform && !app.RequiresStableAPIs(ctx) + checkNativeSdkVersion = app.SdkVersion().Specified() && + app.SdkVersion().Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } ctx.WalkDeps(func(module android.Module, parent android.Module) bool { @@ -829,6 +829,10 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { if v := m.MinSdkVersion(); v != "" { toMinSdkVersion = v } + } else if m, ok := to.(interface{ MinSdkVersionString() string }); ok { + if v := m.MinSdkVersionString(); v != "" { + toMinSdkVersion = v + } } depsInfo[depName] = android.ApexModuleDepInfo{ To: depName, @@ -840,7 +844,7 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { return true }) - a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersion(), depsInfo) + a.ApexBundleDepsInfo.BuildDepsInfoLists(ctx, a.MinSdkVersionString(), depsInfo) } func (a *AndroidApp) Updatable() bool { diff --git a/java/app_import.go b/java/app_import.go index d4da64da5..32cec2309 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -394,12 +394,12 @@ func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ androi return false } -func (a *AndroidAppImport) sdkVersion() sdkSpec { - return sdkSpecFrom("") +func (a *AndroidAppImport) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom("") } -func (a *AndroidAppImport) minSdkVersion() sdkSpec { - return sdkSpecFrom("") +func (a *AndroidAppImport) MinSdkVersion() android.SdkSpec { + return android.SdkSpecFrom("") } var _ android.ApexModule = (*AndroidAppImport)(nil) diff --git a/java/app_test.go b/java/app_test.go index 825ad203a..a99ac62da 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -652,7 +652,7 @@ func TestLibraryAssets(t *testing.T) { } else { aapt2link = m.Output("package-res.apk") } - aapt2link = aapt2link.RelativeToTop() + aapt2link = aapt2link aapt2Flags := aapt2link.Args["flags"] if test.assetFlag != "" { android.AssertStringDoesContain(t, "asset flag", aapt2Flags, test.assetFlag) @@ -1993,14 +1993,14 @@ func TestOverrideAndroidAppDependency(t *testing.T) { `) // Verify baz, which depends on the overridden module foo, has the correct classpath javac arg. - javac := ctx.ModuleForTests("baz", "android_common").Rule("javac").RelativeToTop() + javac := ctx.ModuleForTests("baz", "android_common").Rule("javac") fooTurbine := "out/soong/.intermediates/foo/android_common/turbine-combined/foo.jar" if !strings.Contains(javac.Args["classpath"], fooTurbine) { t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine) } // Verify qux, which depends on the overriding module bar, has the correct classpath javac arg. - javac = ctx.ModuleForTests("qux", "android_common").Rule("javac").RelativeToTop() + javac = ctx.ModuleForTests("qux", "android_common").Rule("javac") barTurbine := "out/soong/.intermediates/foo/android_common_bar/turbine-combined/foo.jar" if !strings.Contains(javac.Args["classpath"], barTurbine) { t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine) @@ -2077,7 +2077,7 @@ func TestOverrideAndroidTest(t *testing.T) { } // Check if javac classpath has the correct jar file path. This checks instrumentation_for overrides. - javac := variant.Rule("javac").RelativeToTop() + javac := variant.Rule("javac") turbine := filepath.Join("out", "soong", ".intermediates", "foo", expected.targetVariant, "turbine-combined", "foo.jar") if !strings.Contains(javac.Args["classpath"], turbine) { t.Errorf("classpath %q does not contain %q", javac.Args["classpath"], turbine) @@ -2151,7 +2151,7 @@ func TestAndroidTest_FixTestConfig(t *testing.T) { for _, test := range testCases { variant := ctx.ModuleForTests(test.moduleName, test.variantName) - params := variant.MaybeOutput("test_config_fixer/AndroidTest.xml").RelativeToTop() + params := variant.MaybeOutput("test_config_fixer/AndroidTest.xml") if len(test.expectedFlags) > 0 { if params.Rule == nil { @@ -2647,14 +2647,14 @@ func TestEmbedNotice(t *testing.T) { t.Errorf("GENRULE_NOTICE is missing from notice files, %q", noticeInputs) } // aapt2 flags should include -A <NOTICE dir> so that its contents are put in the APK's /assets. - res := foo.Output("package-res.apk").RelativeToTop() + res := foo.Output("package-res.apk") aapt2Flags := res.Args["flags"] e := "-A out/soong/.intermediates/foo/android_common/NOTICE" android.AssertStringDoesContain(t, "expected.apkPath", aapt2Flags, e) // bar has NOTICE files to process, but embed_notices is not set. bar := result.ModuleForTests("bar", "android_common") - res = bar.Output("package-res.apk").RelativeToTop() + res = bar.Output("package-res.apk") aapt2Flags = res.Args["flags"] e = "-A out/soong/.intermediates/bar/android_common/NOTICE" android.AssertStringDoesNotContain(t, "bar shouldn't have the asset dir flag for NOTICE", aapt2Flags, e) diff --git a/java/base.go b/java/base.go index bd394af63..73e5352f0 100644 --- a/java/base.go +++ b/java/base.go @@ -373,11 +373,11 @@ type Module struct { } func (j *Module) CheckStableSdkVersion() error { - sdkVersion := j.sdkVersion() - if sdkVersion.stable() { + sdkVersion := j.SdkVersion() + if sdkVersion.Stable() { return nil } - if sdkVersion.kind == sdkCorePlatform { + if sdkVersion.Kind == android.SdkCorePlatform { if useLegacyCorePlatformApiByName(j.BaseModuleName()) { return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion) } else { @@ -392,8 +392,8 @@ func (j *Module) CheckStableSdkVersion() error { // checkSdkVersions enforces restrictions around SDK dependencies. func (j *Module) checkSdkVersions(ctx android.ModuleContext) { if j.RequiresStableAPIs(ctx) { - if sc, ok := ctx.Module().(sdkContext); ok { - if !sc.sdkVersion().specified() { + if sc, ok := ctx.Module().(android.SdkContext); ok { + if !sc.SdkVersion().Specified() { ctx.PropertyErrorf("sdk_version", "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).") } @@ -416,9 +416,9 @@ func (j *Module) checkSdkVersions(ctx android.ModuleContext) { } func (j *Module) checkPlatformAPI(ctx android.ModuleContext) { - if sc, ok := ctx.Module().(sdkContext); ok { + if sc, ok := ctx.Module().(android.SdkContext); ok { usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis) - sdkVersionSpecified := sc.sdkVersion().specified() + sdkVersionSpecified := sc.SdkVersion().Specified() if usePlatformAPI && sdkVersionSpecified { ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.") } else if !usePlatformAPI && !sdkVersionSpecified { @@ -512,30 +512,30 @@ func (j *Module) shouldInstrumentInApex(ctx android.BaseModuleContext) bool { return false } -func (j *Module) sdkVersion() sdkSpec { - return sdkSpecFrom(String(j.deviceProperties.Sdk_version)) +func (j *Module) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom(String(j.deviceProperties.Sdk_version)) } -func (j *Module) systemModules() string { +func (j *Module) SystemModules() string { return proptools.String(j.deviceProperties.System_modules) } -func (j *Module) minSdkVersion() sdkSpec { +func (j *Module) MinSdkVersion() android.SdkSpec { if j.deviceProperties.Min_sdk_version != nil { - return sdkSpecFrom(*j.deviceProperties.Min_sdk_version) + return android.SdkSpecFrom(*j.deviceProperties.Min_sdk_version) } - return j.sdkVersion() + return j.SdkVersion() } -func (j *Module) targetSdkVersion() sdkSpec { +func (j *Module) TargetSdkVersion() android.SdkSpec { if j.deviceProperties.Target_sdk_version != nil { - return sdkSpecFrom(*j.deviceProperties.Target_sdk_version) + return android.SdkSpecFrom(*j.deviceProperties.Target_sdk_version) } - return j.sdkVersion() + return j.SdkVersion() } -func (j *Module) MinSdkVersion() string { - return j.minSdkVersion().version.String() +func (j *Module) MinSdkVersionString() string { + return j.MinSdkVersion().Version.String() } func (j *Module) AvailableFor(what string) bool { @@ -552,7 +552,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) - sdkDeps(ctx, sdkContext(j), j.dexer) + sdkDeps(ctx, android.SdkContext(j), j.dexer) if j.deviceProperties.SyspropPublicStub != "" { // This is a sysprop implementation library that has a corresponding sysprop public @@ -702,7 +702,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB var flags javaBuilderFlags // javaVersion flag. - flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j)) + flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j)) if ctx.Config().RunErrorProne() { if config.ErrorProneClasspath == nil && ctx.Config().TestProductVariables == nil { @@ -731,7 +731,7 @@ func (j *Module) collectBuilderFlags(ctx android.ModuleContext, deps deps) javaB flags.processors = android.FirstUniqueStrings(flags.processors) if len(flags.bootClasspath) == 0 && ctx.Host() && !flags.javaVersion.usesJavaModules() && - decodeSdkDep(ctx, sdkContext(j)).hasStandardLibs() { + decodeSdkDep(ctx, android.SdkContext(j)).hasStandardLibs() { // Give host-side tools a version of OpenJDK's standard libraries // close to what they're targeting. As of Dec 2017, AOSP is only // bundling OpenJDK 8 and 9, so nothing < 8 is available. @@ -1209,7 +1209,7 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } // Dex compilation var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) if ctx.Failed() { return } @@ -1254,8 +1254,8 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { } if ctx.Device() { - lintSDKVersionString := func(sdkSpec sdkSpec) string { - if v := sdkSpec.version; v.isNumbered() { + lintSDKVersionString := func(sdkSpec android.SdkSpec) string { + if v := sdkSpec.Version; v.IsNumbered() { return v.String() } else { return ctx.Config().DefaultAppTargetSdk(ctx).String() @@ -1267,9 +1267,9 @@ func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) { j.linter.srcJars = srcJars j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...) j.linter.classes = j.implementationJarFile - j.linter.minSdkVersion = lintSDKVersionString(j.minSdkVersion()) - j.linter.targetSdkVersion = lintSDKVersionString(j.targetSdkVersion()) - j.linter.compileSdkVersion = lintSDKVersionString(j.sdkVersion()) + j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion()) + j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion()) + j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion()) j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { @@ -1471,14 +1471,14 @@ func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - sdkSpec := j.minSdkVersion() - if !sdkSpec.specified() { + sdkSpec := j.MinSdkVersion() + if !sdkSpec.Specified() { return fmt.Errorf("min_sdk_version is not specified") } - if sdkSpec.kind == sdkCore { + if sdkSpec.Kind == android.SdkCore { return nil } - ver, err := sdkSpec.effectiveVersion(ctx) + ver, err := sdkSpec.EffectiveVersion(ctx) if err != nil { return err } @@ -1576,24 +1576,24 @@ func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) { return linkType, true } - ver := m.sdkVersion() - switch ver.kind { - case sdkCore: + ver := m.SdkVersion() + switch ver.Kind { + case android.SdkCore: return javaCore, false - case sdkSystem: + case android.SdkSystem: return javaSystem, false - case sdkPublic: + case android.SdkPublic: return javaSdk, false - case sdkModule: + case android.SdkModule: return javaModule, false - case sdkSystemServer: + case android.SdkSystemServer: return javaSystemServer, false - case sdkPrivate, sdkNone, sdkCorePlatform, sdkTest: + case android.SdkPrivate, android.SdkNone, android.SdkCorePlatform, android.SdkTest: return javaPlatform, false } - if !ver.valid() { - panic(fmt.Errorf("sdk_version is invalid. got %q", ver.raw)) + if !ver.Valid() { + panic(fmt.Errorf("sdk_version is invalid. got %q", ver.Raw)) } return javaSdk, false } @@ -1625,7 +1625,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { var deps deps if ctx.Device() { - sdkDep := decodeSdkDep(ctx, sdkContext(j)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.invalidVersion { ctx.AddMissingDependencies(sdkDep.bootclasspath) ctx.AddMissingDependencies(sdkDep.java9Classpath) @@ -1656,7 +1656,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) case staticLibTag: ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName) } diff --git a/java/boot_image.go b/java/boot_image.go index 8594792b5..0c4797609 100644 --- a/java/boot_image.go +++ b/java/boot_image.go @@ -70,16 +70,20 @@ var bootImageContentDepTag = bootImageContentDependencyTag{} var _ android.ExcludeFromVisibilityEnforcementTag = bootImageContentDepTag +func IsbootImageContentDepTag(tag blueprint.DependencyTag) bool { + return tag == bootImageContentDepTag +} + type bootImageProperties struct { // The name of the image this represents. // - // Must be one of "art" or "boot". + // If specified then it must be one of "art" or "boot". Image_name *string // The contents of this boot image, could be either java_library, java_sdk_library, or boot_image. // // The order of this list matters as it is the order that is used in the bootclasspath. - Contents []string `blueprint:"mutated"` + Contents []string } type BootImageModule struct { @@ -104,6 +108,13 @@ func bootImageFactory() android.Module { } func bootImageConsistencyCheck(ctx android.EarlyModuleContext, m *BootImageModule) { + contents := m.properties.Contents + if m.properties.Image_name == nil && len(contents) == 0 { + ctx.ModuleErrorf(`neither of the "image_name" and "contents" properties have been supplied, please supply exactly one`) + } + if m.properties.Image_name != nil && len(contents) != 0 { + ctx.ModuleErrorf(`both of the "image_name" and "contents" properties have been supplied, please supply exactly one`) + } imageName := proptools.String(m.properties.Image_name) if imageName == "art" { // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is @@ -175,8 +186,8 @@ func (i BootImageInfo) AndroidBootImageFilesByArchType() map[android.ArchType]an func (b *BootImageModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { tag := ctx.OtherModuleDependencyTag(dep) if tag == bootImageContentDepTag { - // Boot image contents are not automatically added to apex, yet. - return false + // Boot image contents are automatically added to apex. + return true } if android.IsMetaDependencyTag(tag) { // Cross-cutting metadata dependencies are metadata. diff --git a/java/boot_image_test.go b/java/boot_image_test.go index a289df877..e1866dedc 100644 --- a/java/boot_image_test.go +++ b/java/boot_image_test.go @@ -101,3 +101,27 @@ func TestBootImageInconsistentArtConfiguration_ApexMixture(t *testing.T) { } `) } + +func TestBootImageWithoutImageNameOrContents(t *testing.T) { + prepareForTestWithBootImage. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\Qneither of the "image_name" and "contents" properties\E`)). + RunTestWithBp(t, ` + boot_image { + name: "boot-image", + } + `) +} + +func TestBootImageWithImageNameAndContents(t *testing.T) { + prepareForTestWithBootImage. + ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\Qboth of the "image_name" and "contents" properties\E`)). + RunTestWithBp(t, ` + boot_image { + name: "boot-image", + image_name: "boot", + contents: ["other"], + } + `) +} diff --git a/java/config/kotlin.go b/java/config/kotlin.go index fd8e3dbe9..6cb61f306 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -35,11 +35,16 @@ func init() { pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar") pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar) - // These flags silence "Illegal reflective access" warnings when running kotlinc in OpenJDK9 - pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{ + // These flags silence "Illegal reflective access" warnings when running kapt in OpenJDK9+ + pctx.StaticVariable("KaptSuppressJDK9Warnings", strings.Join([]string{ "-J--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", "-J--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", "-J--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", "-J--add-opens=java.base/sun.net.www.protocol.jar=ALL-UNNAMED", }, " ")) + + // These flags silence "Illegal reflective access" warnings when running kotlinc in OpenJDK9+ + pctx.StaticVariable("KotlincSuppressJDK9Warnings", strings.Join([]string{ + "-J--add-opens=java.base/java.util=ALL-UNNAMED", // https://youtrack.jetbrains.com/issue/KT-43704 + }, " ")) } diff --git a/java/dex.go b/java/dex.go index b042f133f..5c6d41d87 100644 --- a/java/dex.go +++ b/java/dex.go @@ -157,7 +157,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir", "r8Flags", "zipFlags"}, []string{"implicits"}) -func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string { +func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion android.SdkSpec) []string { flags := d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated // to D8 flags. See: b/69377755 @@ -174,12 +174,12 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) "--verbose") } - effectiveVersion, err := minSdkVersion.effectiveVersion(ctx) + effectiveVersion, err := minSdkVersion.EffectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("min_sdk_version", "%s", err) } - flags = append(flags, "--min-api "+effectiveVersion.asNumberString()) + flags = append(flags, "--min-api "+effectiveVersion.AsNumberString()) return flags } @@ -266,7 +266,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl return r8Flags, r8Deps } -func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion sdkSpec, +func (d *dexer) compileDex(ctx android.ModuleContext, flags javaBuilderFlags, minSdkVersion android.SdkSpec, classesJar android.Path, jarName string) android.OutputPath { // Compile classes.jar into classes.dex and then javalib.jar diff --git a/java/droiddoc.go b/java/droiddoc.go index a8e2b0e48..a0d99a7af 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -226,11 +226,8 @@ type Javadoc struct { srcJars android.Paths srcFiles android.Paths sourcepaths android.Paths - argFiles android.Paths implicits android.Paths - args []string - docZip android.WritablePath stubsSrcJar android.WritablePath } @@ -268,25 +265,25 @@ func JavadocHostFactory() android.Module { var _ android.OutputFileProducer = (*Javadoc)(nil) -func (j *Javadoc) sdkVersion() sdkSpec { - return sdkSpecFrom(String(j.properties.Sdk_version)) +func (j *Javadoc) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom(String(j.properties.Sdk_version)) } -func (j *Javadoc) systemModules() string { +func (j *Javadoc) SystemModules() string { return proptools.String(j.properties.System_modules) } -func (j *Javadoc) minSdkVersion() sdkSpec { - return j.sdkVersion() +func (j *Javadoc) MinSdkVersion() android.SdkSpec { + return j.SdkVersion() } -func (j *Javadoc) targetSdkVersion() sdkSpec { - return j.sdkVersion() +func (j *Javadoc) TargetSdkVersion() android.SdkSpec { + return j.SdkVersion() } func (j *Javadoc) addDeps(ctx android.BottomUpMutatorContext) { if ctx.Device() { - sdkDep := decodeSdkDep(ctx, sdkContext(j)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.useModule { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) ctx.AddVariationDependencies(nil, systemModulesTag, sdkDep.systemModules) @@ -364,7 +361,7 @@ func (j *Javadoc) genSources(ctx android.ModuleContext, srcFiles android.Paths, func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { var deps deps - sdkDep := decodeSdkDep(ctx, sdkContext(j)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.invalidVersion { ctx.AddMissingDependencies(sdkDep.bootclasspath) ctx.AddMissingDependencies(sdkDep.java9Classpath) @@ -393,7 +390,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } case libTag: if dep, ok := module.(SdkLibraryDependency); ok { - deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) + deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) } else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) { dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo) deps.classpath = append(deps.classpath, dep.HeaderJars...) @@ -480,15 +477,20 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { j.sourcepaths = android.PathsForModuleSrc(ctx, []string{"."}) } - j.argFiles = android.PathsForModuleSrc(ctx, j.properties.Arg_files) + return deps +} + +func (j *Javadoc) expandArgs(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { + var argFiles android.Paths argFilesMap := map[string]string{} argFileLabels := []string{} for _, label := range j.properties.Arg_files { var paths = android.PathsForModuleSrc(ctx, []string{label}) if _, exists := argFilesMap[label]; !exists { - argFilesMap[label] = strings.Join(paths.Strings(), " ") + argFilesMap[label] = strings.Join(cmd.PathsForInputs(paths), " ") argFileLabels = append(argFileLabels, label) + argFiles = append(argFiles, paths...) } else { ctx.ModuleErrorf("multiple arg_files for %q, %q and %q", label, argFilesMap[label], paths) @@ -508,7 +510,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { } for _, flag := range flags { - args, err := android.Expand(flag, func(name string) (string, error) { + expanded, err := android.Expand(flag, func(name string) (string, error) { if strings.HasPrefix(name, "location ") { label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) if paths, ok := argFilesMap[label]; ok { @@ -526,10 +528,10 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { if err != nil { ctx.PropertyErrorf(argsPropertyName, "%s", err.Error()) } - j.args = append(j.args, args) + cmd.Flag(expanded) } - return deps + cmd.Implicits(argFiles) } func (j *Javadoc) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -553,7 +555,7 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { srcJarList := zipSyncCmd(ctx, rule, srcJarDir, j.srcJars) - javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j)) + javaVersion := getJavaVersion(ctx, String(j.properties.Java_version), android.SdkContext(j)) cmd := javadocSystemModulesCmd(ctx, rule, j.srcFiles, outDir, srcJarDir, srcJarList, deps.systemModules, deps.classpath, j.sourcepaths) @@ -563,6 +565,8 @@ func (j *Javadoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { Flag("-XDignore.symbol.file"). Flag("-Xdoclint:none") + j.expandArgs(ctx, cmd) + rule.Command(). BuiltTool("soong_zip"). Flag("-write_if_changed"). @@ -821,7 +825,7 @@ func (d *Droiddoc) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps.bootClasspath, deps.classpath, d.Javadoc.sourcepaths) } - cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) + d.expandArgs(ctx, cmd) if d.properties.Compat_config != nil { compatConfig := android.PathForModuleSrc(ctx, String(d.properties.Compat_config)) diff --git a/java/droiddoc_test.go b/java/droiddoc_test.go index 2b324aef1..8d1f5917c 100644 --- a/java/droiddoc_test.go +++ b/java/droiddoc_test.go @@ -80,7 +80,7 @@ func TestDroiddoc(t *testing.T) { barStubsOutput := barStubsOutputs[0] barDoc := ctx.ModuleForTests("bar-doc", "android_common") - javaDoc := barDoc.Rule("javadoc").RelativeToTop() + javaDoc := barDoc.Rule("javadoc") if g, w := android.PathsRelativeToTop(javaDoc.Implicits), android.PathRelativeToTop(barStubsOutput); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) } diff --git a/java/droidstubs.go b/java/droidstubs.go index e453e62d6..34696165d 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -284,7 +284,7 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru cmd.Flag("--include-annotations") validatingNullability := - android.InList("--validate-nullability-from-merged-stubs", d.Javadoc.args) || + strings.Contains(String(d.Javadoc.properties.Args), "--validate-nullability-from-merged-stubs") || String(d.properties.Validate_nullability_from_list) != "" migratingNullability := String(d.properties.Previous_api) != "" @@ -360,7 +360,16 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { if t, ok := m.(*ExportedDroiddocDir); ok { for _, dep := range t.deps { - if strings.HasSuffix(dep.String(), filename) { + if dep.Base() == filename { + cmd.Implicit(dep) + } + if filename != "android.jar" && dep.Base() == "android.jar" { + // Metalava implicitly searches these patterns: + // prebuilts/tools/common/api-versions/android-%/android.jar + // prebuilts/sdk/%/public/android.jar + // Add android.jar files from the api_levels_annotations_dirs directories to try + // to satisfy these patterns. If Metalava can't find a match for an API level + // between 1 and 28 in at least one pattern it will fail. cmd.Implicit(dep) } } @@ -465,7 +474,7 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps := d.Javadoc.collectDeps(ctx) - javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), sdkContext(d)) + javaVersion := getJavaVersion(ctx, String(d.Javadoc.properties.Java_version), android.SdkContext(d)) // Create rule for metalava @@ -473,7 +482,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule := android.NewRuleBuilder(pctx, ctx) - sandbox := proptools.Bool(d.Javadoc.properties.Sandbox) + sandbox := proptools.BoolDefault(d.Javadoc.properties.Sandbox, true) if sandbox { rule.Sbox(android.PathForModuleOut(ctx, "metalava"), android.PathForModuleOut(ctx, "metalava.sbox.textproto")). @@ -509,14 +518,8 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { d.inclusionAnnotationsFlags(ctx, cmd) d.apiLevelsAnnotationsFlags(ctx, cmd) - if android.InList("--generate-documentation", d.Javadoc.args) { - // Currently Metalava have the ability to invoke Javadoc in a separate process. - // Pass "-nodocs" to suppress the Javadoc invocation when Metalava receives - // "--generate-documentation" arg. This is not needed when Metalava removes this feature. - d.Javadoc.args = append(d.Javadoc.args, "-nodocs") - } + d.expandArgs(ctx, cmd) - cmd.Flag(strings.Join(d.Javadoc.args, " ")).Implicits(d.Javadoc.argFiles) for _, o := range d.Javadoc.properties.Out { cmd.ImplicitOutput(android.PathForModuleGen(ctx, o)) } diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index c6db97901..f8125fb8c 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -34,6 +34,7 @@ func TestDroidstubs(t *testing.T) { srcs: ["bar-doc/a.java"], api_levels_annotations_dirs: ["droiddoc-templates-sdk"], api_levels_annotations_enabled: true, + sandbox: false, } droidstubs { @@ -43,6 +44,7 @@ func TestDroidstubs(t *testing.T) { api_levels_annotations_dirs: ["droiddoc-templates-sdk"], api_levels_annotations_enabled: true, api_levels_jar_filename: "android.other.jar", + sandbox: false, } `, map[string][]byte{ @@ -81,10 +83,19 @@ func TestDroidstubs(t *testing.T) { func TestDroidstubsSandbox(t *testing.T) { ctx, _ := testJavaWithFS(t, ` + genrule { + name: "foo", + out: ["foo.txt"], + cmd: "touch $(out)", + } + droidstubs { name: "bar-stubs", srcs: ["bar-doc/a.java"], sandbox: true, + + args: "--reference $(location :foo)", + arg_files: [":foo"], } `, map[string][]byte{ @@ -96,6 +107,11 @@ func TestDroidstubsSandbox(t *testing.T) { if g, w := metalava.Inputs.Strings(), []string{"bar-doc/a.java"}; !reflect.DeepEqual(w, g) { t.Errorf("Expected inputs %q, got %q", w, g) } + + manifest := android.RuleBuilderSboxProtoForTests(t, m.Output("metalava.sbox.textproto")) + if g, w := manifest.Commands[0].GetCommand(), "reference __SBOX_SANDBOX_DIR__/out/.intermediates/foo/gen/foo.txt"; !strings.Contains(g, w) { + t.Errorf("Expected command to contain %q, got %q", w, g) + } } func TestDroidstubsWithSystemModules(t *testing.T) { diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index d6c6a2ddc..5c449e506 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -39,7 +39,8 @@ var hiddenApiFixtureFactory = android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithHiddenApiBuildComponents) func TestHiddenAPISingleton(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { @@ -50,13 +51,14 @@ func TestHiddenAPISingleton(t *testing.T) { `) hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi").RelativeToTop() + hiddenapiRule := hiddenAPI.Rule("hiddenapi") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPIIndexSingleton(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("bar"), fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"), @@ -115,7 +117,8 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) " replaced by the prebuilt module \"prebuilt_foo\" but unfortunately it does not provide a" + " suitable boot dex jar" - hiddenApiFixtureFactory.Extend( + android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)). RunTestWithBp(t, ` @@ -134,7 +137,8 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) } func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_import { @@ -145,13 +149,14 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { `) hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi").RelativeToTop() + hiddenapiRule := hiddenAPI.Rule("hiddenapi") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { @@ -169,7 +174,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { `) hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi").RelativeToTop() + hiddenapiRule := hiddenAPI.Rule("hiddenapi") fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) @@ -178,7 +183,8 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { } func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), ).RunTestWithBp(t, ` java_library { @@ -196,7 +202,7 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { `) hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi").RelativeToTop() + hiddenapiRule := hiddenAPI.Rule("hiddenapi") prebuiltJarArg := "--boot-dex=out/soong/.intermediates/prebuilt_foo/android_common/dex/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) @@ -236,7 +242,8 @@ func TestHiddenAPISingletonSdks(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, tc.preparer, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild) @@ -244,7 +251,7 @@ func TestHiddenAPISingletonSdks(t *testing.T) { ).RunTest(t) hiddenAPI := result.SingletonForTests("hiddenapi") - hiddenapiRule := hiddenAPI.Rule("hiddenapi").RelativeToTop() + hiddenapiRule := hiddenAPI.Rule("hiddenapi") wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) @@ -286,7 +293,8 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { // Where to find the prebuilt hiddenapi files: prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi" - result := hiddenApiFixtureFactory.Extend( + result := android.GroupFixturePreparers( + hiddenApiFixtureFactory, fixtureSetBootJarsProductVariable("platform:foo"), fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir), ).RunTestWithBp(t, ` @@ -307,7 +315,7 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { cpRule := hiddenAPI.Rule("Cp") actualCpInput := cpRule.BuildParams.Input actualCpOutput := cpRule.BuildParams.Output - encodeDexRule := foo.Rule("hiddenAPIEncodeDex").RelativeToTop() + encodeDexRule := foo.Rule("hiddenAPIEncodeDex") actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"] android.AssertPathRelativeToTopEquals(t, "hiddenapi cp rule input", expectedCpInput, actualCpInput) diff --git a/java/java.go b/java/java.go index 9786947f7..5fe8814f5 100644 --- a/java/java.go +++ b/java/java.go @@ -33,12 +33,12 @@ import ( ) func init() { - RegisterJavaBuildComponents(android.InitRegistrationContext) + registerJavaBuildComponents(android.InitRegistrationContext) RegisterJavaSdkMemberTypes() } -func RegisterJavaBuildComponents(ctx android.RegistrationContext) { +func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("java_defaults", DefaultsFactory) ctx.RegisterModuleType("java_library", LibraryFactory) @@ -304,7 +304,7 @@ type jniLib struct { unstrippedFile android.Path } -func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext sdkContext, d dexer) { +func sdkDeps(ctx android.BottomUpMutatorContext, sdkContext android.SdkContext, d dexer) { sdkDep := decodeSdkDep(ctx, sdkContext) if sdkDep.useModule { ctx.AddVariationDependencies(nil, bootClasspathTag, sdkDep.bootclasspath...) @@ -352,11 +352,11 @@ func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer } } -func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext sdkContext) javaVersion { +func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext android.SdkContext) javaVersion { if javaVersion != "" { return normalizeJavaVersion(ctx, javaVersion) } else if ctx.Device() { - return sdkContext.sdkVersion().defaultJavaLanguageVersion(ctx) + return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion()) } else { return JAVA_VERSION_9 } @@ -776,7 +776,7 @@ func (j *TestHost) AddExtraResource(p android.Path) { func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { if j.testProperties.Test_options.Unit_test == nil && ctx.Host() { // TODO(b/): Clean temporary heuristic to avoid unexpected onboarding. - defaultUnitTest := !inList("tradefed", j.properties.Static_libs) && !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites) + defaultUnitTest := !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites) j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest) } j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template, @@ -1074,8 +1074,14 @@ func BinaryHostFactory() android.Module { type ImportProperties struct { Jars []string `android:"path,arch_variant"` + // The version of the SDK that the source prebuilt file was built against. Defaults to the + // current version if not specified. Sdk_version *string + // The minimum version of the SDK that this module supports. Defaults to sdk_version if not + // specified. + Min_sdk_version *string + Installable *bool // List of shared java libs that this module has dependencies to @@ -1126,28 +1132,31 @@ type Import struct { hideApexVariantFromMake bool } -func (j *Import) sdkVersion() sdkSpec { - return sdkSpecFrom(String(j.properties.Sdk_version)) +func (j *Import) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom(String(j.properties.Sdk_version)) } func (j *Import) makeSdkVersion() string { - return j.sdkVersion().raw + return j.SdkVersion().Raw } -func (j *Import) systemModules() string { +func (j *Import) SystemModules() string { return "none" } -func (j *Import) minSdkVersion() sdkSpec { - return j.sdkVersion() +func (j *Import) MinSdkVersion() android.SdkSpec { + if j.properties.Min_sdk_version != nil { + return android.SdkSpecFrom(*j.properties.Min_sdk_version) + } + return j.SdkVersion() } -func (j *Import) targetSdkVersion() sdkSpec { - return j.sdkVersion() +func (j *Import) TargetSdkVersion() android.SdkSpec { + return j.SdkVersion() } -func (j *Import) MinSdkVersion() string { - return j.minSdkVersion().version.String() +func (j *Import) MinSdkVersionString() string { + return j.MinSdkVersion().Version.String() } func (j *Import) Prebuilt() *android.Prebuilt { @@ -1178,7 +1187,7 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) if ctx.Device() && Bool(j.dexProperties.Compile_dex) { - sdkDeps(ctx, sdkContext(j), j.dexer) + sdkDeps(ctx, android.SdkContext(j), j.dexer) } } @@ -1221,7 +1230,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else if dep, ok := module.(SdkLibraryDependency); ok { switch tag { case libTag: - flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...) + flags.classpath = append(flags.classpath, dep.SdkHeaderJars(ctx, j.SdkVersion())...) } } @@ -1263,7 +1272,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.ModuleErrorf("internal error: no dex implementation jar available from prebuilt_apex %q", deapexerModule.Name()) } } else if Bool(j.dexProperties.Compile_dex) { - sdkDep := decodeSdkDep(ctx, sdkContext(j)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(j)) if sdkDep.invalidVersion { ctx.AddMissingDependencies(sdkDep.bootclasspath) ctx.AddMissingDependencies(sdkDep.java9Classpath) @@ -1282,7 +1291,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex var dexOutputFile android.OutputPath - dexOutputFile = j.dexer.compileDex(ctx, flags, j.minSdkVersion(), outputFile, jarName) + dexOutputFile = j.dexer.compileDex(ctx, flags, j.MinSdkVersion(), outputFile, jarName) if ctx.Failed() { return } @@ -1350,7 +1359,20 @@ func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // Implements android.ApexModule func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - // Do not check for prebuilts against the min_sdk_version of enclosing APEX + sdkSpec := j.MinSdkVersion() + if !sdkSpec.Specified() { + return fmt.Errorf("min_sdk_version is not specified") + } + if sdkSpec.Kind == android.SdkCore { + return nil + } + ver, err := sdkSpec.EffectiveVersion(ctx) + if err != nil { + return err + } + if ver.ApiLevel(ctx).GreaterThan(sdkVersion) { + return fmt.Errorf("newer SDK(%v)", ver) + } return nil } diff --git a/java/java_test.go b/java/java_test.go index 2ade0fed8..fdf757902 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -74,23 +74,6 @@ func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContex return result.TestContext, result.Config } -// testJavaErrorWithConfig is a legacy way of running tests of java modules that expect errors. -// -// See testJava for an explanation as to how to stop using this deprecated method. -// -// deprecated -func testJavaErrorWithConfig(t *testing.T, pattern string, config android.Config) (*android.TestContext, android.Config) { - t.Helper() - // This must be done on the supplied config and not as part of the fixture because any changes to - // the fixture's config will be ignored when RunTestWithConfig replaces it. - pathCtx := android.PathContextForTesting(config) - dexpreopt.SetTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx)) - result := prepareForJavaTest. - ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)). - RunTestWithConfig(t, config) - return result.TestContext, result.Config -} - // testJavaWithFS runs tests using the prepareForJavaTest // // See testJava for an explanation as to how to stop using this deprecated method. @@ -250,7 +233,7 @@ func TestSimple(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac").RelativeToTop() + javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { @@ -845,7 +828,12 @@ func TestJavaSdkLibraryEnforce(t *testing.T) { if expectedErrorPattern != "" { errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern) } - prepareForJavaTest.ExtendWithErrorHandler(errorHandler).RunTest(t, createPreparer(info)) + android.GroupFixturePreparers( + prepareForJavaTest, + createPreparer(info), + ). + ExtendWithErrorHandler(errorHandler). + RunTest(t) }) } @@ -976,7 +964,7 @@ func TestDefaults(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac").RelativeToTop() + javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { @@ -1336,11 +1324,11 @@ func TestTurbine(t *testing.T) { } `) - fooTurbine := result.ModuleForTests("foo", "android_common").Rule("turbine").RelativeToTop() - barTurbine := result.ModuleForTests("bar", "android_common").Rule("turbine").RelativeToTop() - barJavac := result.ModuleForTests("bar", "android_common").Rule("javac").RelativeToTop() - barTurbineCombined := result.ModuleForTests("bar", "android_common").Description("for turbine").RelativeToTop() - bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac").RelativeToTop() + fooTurbine := result.ModuleForTests("foo", "android_common").Rule("turbine") + barTurbine := result.ModuleForTests("bar", "android_common").Rule("turbine") + barJavac := result.ModuleForTests("bar", "android_common").Rule("javac") + barTurbineCombined := result.ModuleForTests("bar", "android_common").Description("for turbine") + bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") android.AssertPathsRelativeToTopEquals(t, "foo inputs", []string{"a.java"}, fooTurbine.Inputs) @@ -1363,7 +1351,7 @@ func TestSharding(t *testing.T) { barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar") for i := 0; i < 3; i++ { - barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i)).RelativeToTop() + barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i)) if !strings.Contains(barJavac.Args["classpath"], barHeaderJar) { t.Errorf("bar javac classpath %v does not contain %q", barJavac.Args["classpath"], barHeaderJar) } @@ -1670,7 +1658,7 @@ func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { // The bar library should depend on the stubs jar. barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") - if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } @@ -1973,7 +1961,7 @@ func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) { `) // The baz library should depend on the system stubs jar. bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac") - if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { + if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } diff --git a/java/kotlin.go b/java/kotlin.go index 2960f819d..3a6fc0f48 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -34,8 +34,9 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.JavacHeapFlags} $kotlincFlags ` + - `-jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile -kotlin-home $emptyDir && ` + + `${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + `$kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` + + `-kotlin-home $emptyDir && ` + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ @@ -123,8 +124,8 @@ var kapt = pctx.AndroidRemoteStaticRule("kapt", android.RemoteRuleSupports{Goma: `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} $kotlincFlags ` + - `-Xplugin=${config.KotlinKaptJar} ` + + `${config.KotlincCmd} ${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` + + `${config.JavacHeapFlags} $kotlincFlags -Xplugin=${config.KotlinKaptJar} ` + `-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` + `-P plugin:org.jetbrains.kotlin.kapt3:classes=$kaptDir/classes ` + `-P plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptDir/stubs ` + diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go new file mode 100644 index 000000000..550707754 --- /dev/null +++ b/java/platform_bootclasspath.go @@ -0,0 +1,74 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "android/soong/dexpreopt" +) + +func init() { + registerPlatformBootclasspathBuildComponents(android.InitRegistrationContext) +} + +func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory) +} + +type platformBootclasspathModule struct { + android.ModuleBase +} + +func platformBootclasspathFactory() android.Module { + m := &platformBootclasspathModule{} + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { + if SkipDexpreoptBootJars(ctx) { + return + } + + // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The + // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). + dexpreopt.RegisterToolDeps(ctx) +} + +func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Nothing to do if skipping the dexpreopt of boot image jars. + if SkipDexpreoptBootJars(ctx) { + return + } + + // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars + // GenerateSingletonBuildActions method as it cannot create it for itself. + dexpreopt.GetGlobalSoongConfig(ctx) + + imageConfig := b.getImageConfig(ctx) + if imageConfig == nil { + return + } + + // Construct the boot image info from the config. + info := BootImageInfo{imageConfig: imageConfig} + + // Make it available for other modules. + ctx.SetProvider(BootImageInfoProvider, info) +} + +func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { + return defaultBootImageConfig(ctx) +} diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go new file mode 100644 index 000000000..1c81cfdc2 --- /dev/null +++ b/java/platform_bootclasspath_test.go @@ -0,0 +1,38 @@ +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "testing" + + "android/soong/android" + "android/soong/dexpreopt" +) + +// Contains some simple tests for platform_bootclasspath. + +var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + dexpreopt.PrepareForTestByEnablingDexpreopt, +) + +func TestPlatformBootclasspath(t *testing.T) { + prepareForTestWithPlatformBootclasspath. + RunTestWithBp(t, ` + platform_bootclasspath { + name: "platform-bootclasspath", + } + `) +} diff --git a/java/rro.go b/java/rro.go index aafa88e3b..4ae0014db 100644 --- a/java/rro.go +++ b/java/rro.go @@ -91,7 +91,7 @@ type RuntimeResourceOverlayModule interface { } func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) { - sdkDep := decodeSdkDep(ctx, sdkContext(r)) + sdkDep := decodeSdkDep(ctx, android.SdkContext(r)) if sdkDep.hasFrameworkLibs() { r.aapt.deps(ctx, sdkDep) } @@ -141,23 +141,23 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile) } -func (r *RuntimeResourceOverlay) sdkVersion() sdkSpec { - return sdkSpecFrom(String(r.properties.Sdk_version)) +func (r *RuntimeResourceOverlay) SdkVersion() android.SdkSpec { + return android.SdkSpecFrom(String(r.properties.Sdk_version)) } -func (r *RuntimeResourceOverlay) systemModules() string { +func (r *RuntimeResourceOverlay) SystemModules() string { return "" } -func (r *RuntimeResourceOverlay) minSdkVersion() sdkSpec { +func (r *RuntimeResourceOverlay) MinSdkVersion() android.SdkSpec { if r.properties.Min_sdk_version != nil { - return sdkSpecFrom(*r.properties.Min_sdk_version) + return android.SdkSpecFrom(*r.properties.Min_sdk_version) } - return r.sdkVersion() + return r.SdkVersion() } -func (r *RuntimeResourceOverlay) targetSdkVersion() sdkSpec { - return r.sdkVersion() +func (r *RuntimeResourceOverlay) TargetSdkVersion() android.SdkSpec { + return r.SdkVersion() } func (r *RuntimeResourceOverlay) Certificate() Certificate { diff --git a/java/rro_test.go b/java/rro_test.go index 0a10d93ae..bad60bc16 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -68,7 +68,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { m := result.ModuleForTests("foo", "android_common") // Check AAPT2 link flags. - aapt2Flags := m.Output("package-res.apk").RelativeToTop().Args["flags"] + aapt2Flags := m.Output("package-res.apk").Args["flags"] expectedFlags := []string{"--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"} absentFlags := android.RemoveListFromList(expectedFlags, strings.Split(aapt2Flags, " ")) if len(absentFlags) > 0 { diff --git a/java/sdk.go b/java/sdk.go index 74d5a81a9..b546ca029 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -19,7 +19,6 @@ import ( "path/filepath" "sort" "strconv" - "strings" "android/soong/android" "android/soong/java/config" @@ -38,19 +37,6 @@ var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey") var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey") var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey") -type sdkContext interface { - // sdkVersion returns sdkSpec that corresponds to the sdk_version property of the current module - sdkVersion() sdkSpec - // systemModules returns the system_modules property of the current module, or an empty string if it is not set. - systemModules() string - // minSdkVersion returns sdkSpec that corresponds to the min_sdk_version property of the current module, - // or from sdk_version if it is not set. - minSdkVersion() sdkSpec - // targetSdkVersion returns the sdkSpec that corresponds to the target_sdk_version property of the current module, - // or from sdk_version if it is not set. - targetSdkVersion() sdkSpec -} - func UseApiFingerprint(ctx android.BaseModuleContext) bool { if ctx.Config().UnbundledBuild() && !ctx.Config().AlwaysUsePrebuiltSdks() && @@ -60,209 +46,8 @@ func UseApiFingerprint(ctx android.BaseModuleContext) bool { return false } -// sdkKind represents a particular category of an SDK spec like public, system, test, etc. -type sdkKind int - -const ( - sdkInvalid sdkKind = iota - sdkNone - sdkCore - sdkCorePlatform - sdkPublic - sdkSystem - sdkTest - sdkModule - sdkSystemServer - sdkPrivate -) - -// String returns the string representation of this sdkKind -func (k sdkKind) String() string { - switch k { - case sdkPrivate: - return "private" - case sdkNone: - return "none" - case sdkPublic: - return "public" - case sdkSystem: - return "system" - case sdkTest: - return "test" - case sdkCore: - return "core" - case sdkCorePlatform: - return "core_platform" - case sdkModule: - return "module-lib" - case sdkSystemServer: - return "system-server" - default: - return "invalid" - } -} - -// sdkVersion represents a specific version number of an SDK spec of a particular kind -type sdkVersion int - -const ( - // special version number for a not-yet-frozen SDK - sdkVersionCurrent sdkVersion = sdkVersion(android.FutureApiLevelInt) - // special version number to be used for SDK specs where version number doesn't - // make sense, e.g. "none", "", etc. - sdkVersionNone sdkVersion = sdkVersion(0) -) - -// isCurrent checks if the sdkVersion refers to the not-yet-published version of an sdkKind -func (v sdkVersion) isCurrent() bool { - return v == sdkVersionCurrent -} - -// isNumbered checks if the sdkVersion refers to the published (a.k.a numbered) version of an sdkKind -func (v sdkVersion) isNumbered() bool { - return !v.isCurrent() && v != sdkVersionNone -} - -// String returns the string representation of this sdkVersion. -func (v sdkVersion) String() string { - if v.isCurrent() { - return "current" - } else if v.isNumbered() { - return strconv.Itoa(int(v)) - } - return "(no version)" -} - -func (v sdkVersion) ApiLevel(ctx android.EarlyModuleContext) android.ApiLevel { - return android.ApiLevelOrPanic(ctx, v.String()) -} - -// asNumberString directly converts the numeric value of this sdk version as a string. -// When isNumbered() is true, this method is the same as String(). However, for sdkVersionCurrent -// and sdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"), -// respectively. -func (v sdkVersion) asNumberString() string { - return strconv.Itoa(int(v)) -} - -// sdkSpec represents the kind and the version of an SDK for a module to build against -type sdkSpec struct { - kind sdkKind - version sdkVersion - raw string -} - -func (s sdkSpec) String() string { - return fmt.Sprintf("%s_%s", s.kind, s.version) -} - -// valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the -// specified SDK actually exists. -func (s sdkSpec) valid() bool { - return s.kind != sdkInvalid -} - -// specified checks if this sdkSpec is well-formed and is not "". -func (s sdkSpec) specified() bool { - return s.valid() && s.kind != sdkPrivate -} - -// whether the API surface is managed and versioned, i.e. has .txt file that -// get frozen on SDK freeze and changes get reviewed by API council. -func (s sdkSpec) stable() bool { - if !s.specified() { - return false - } - switch s.kind { - case sdkNone: - // there is nothing to manage and version in this case; de facto stable API. - return true - case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer: - return true - case sdkCorePlatform, sdkTest, sdkPrivate: - return false - default: - panic(fmt.Errorf("unknown sdkKind=%v", s.kind)) - } - return false -} - -// prebuiltSdkAvailableForUnbundledBuilt 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 - // as we don't/can't have prebuilt stub for the versions - return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform -} - -func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec { - // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, - // use it instead of "current" for the vendor partition. - currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() - if currentSdkVersion == "current" { - return s - } - - if s.kind == sdkPublic || s.kind == sdkSystem { - if s.version.isCurrent() { - if i, err := strconv.Atoi(currentSdkVersion); err == nil { - version := sdkVersion(i) - return sdkSpec{s.kind, version, s.raw} - } - panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) - } - } - return s -} - -// usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context. -func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool { - if s.version.isCurrent() { - // "current" can be built from source and be from prebuilt SDK - return ctx.Config().AlwaysUsePrebuiltSdks() - } else if s.version.isNumbered() { - // validation check - if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest && s.kind != sdkModule { - panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind)) - return false - } - // numbered SDKs are always from prebuilt - return true - } - // "", "none", "core_platform" fall here - return false -} - -// effectiveVersion converts an sdkSpec into the concrete sdkVersion that the module -// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) -// it returns android.FutureApiLevel(10000). -func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, error) { - if !s.valid() { - return s.version, fmt.Errorf("invalid sdk version %q", s.raw) - } - - if ctx.DeviceSpecific() || ctx.SocSpecific() { - s = s.forVendorPartition(ctx) - } - if s.version.isNumbered() { - return s.version, nil - } - return sdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil -} - -// effectiveVersionString converts an sdkSpec into the concrete version string that the module -// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) -// it returns the codename (P, Q, R, etc.) -func (s sdkSpec) effectiveVersionString(ctx android.EarlyModuleContext) (string, error) { - ver, err := s.effectiveVersion(ctx) - if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() { - return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil - } - return ver.String(), err -} - -func (s sdkSpec) defaultJavaLanguageVersion(ctx android.EarlyModuleContext) javaVersion { - sdk, err := s.effectiveVersion(ctx) +func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpec) javaVersion { + sdk, err := s.EffectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("sdk_version", "%s", err) } @@ -275,103 +60,27 @@ func (s sdkSpec) defaultJavaLanguageVersion(ctx android.EarlyModuleContext) java } } -func sdkSpecFrom(str string) sdkSpec { - switch str { - // special cases first - case "": - return sdkSpec{sdkPrivate, sdkVersionNone, str} - case "none": - return sdkSpec{sdkNone, sdkVersionNone, str} - case "core_platform": - return sdkSpec{sdkCorePlatform, sdkVersionNone, str} - default: - // the syntax is [kind_]version - sep := strings.LastIndex(str, "_") - - var kindString string - if sep == 0 { - return sdkSpec{sdkInvalid, sdkVersionNone, str} - } else if sep == -1 { - kindString = "" - } else { - kindString = str[0:sep] - } - versionString := str[sep+1 : len(str)] - - var kind sdkKind - switch kindString { - case "": - kind = sdkPublic - case "core": - kind = sdkCore - case "system": - kind = sdkSystem - case "test": - kind = sdkTest - case "module": - kind = sdkModule - case "system_server": - kind = sdkSystemServer - default: - return sdkSpec{sdkInvalid, sdkVersionNone, str} - } - - var version sdkVersion - if versionString == "current" { - version = sdkVersionCurrent - } else if i, err := strconv.Atoi(versionString); err == nil { - version = sdkVersion(i) - } else { - return sdkSpec{sdkInvalid, sdkVersionNone, str} - } - - return sdkSpec{kind, version, str} - } -} - -func (s sdkSpec) validateSystemSdk(ctx android.EarlyModuleContext) bool { - // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module) - // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29, - // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current - if s.kind != sdkSystem || !s.version.isNumbered() { - return true - } - allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions() - if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { - systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions() - if len(systemSdkVersions) > 0 { - allowedVersions = systemSdkVersions - } - } - if len(allowedVersions) > 0 && !android.InList(s.version.String(), allowedVersions) { - ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", - s.raw, allowedVersions) - return false - } - return true -} - -func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep { - sdkVersion := sdkContext.sdkVersion() - if !sdkVersion.valid() { - ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.raw) +func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep { + sdkVersion := sdkContext.SdkVersion() + if !sdkVersion.Valid() { + ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw) return sdkDep{} } if ctx.DeviceSpecific() || ctx.SocSpecific() { - sdkVersion = sdkVersion.forVendorPartition(ctx) + sdkVersion = sdkVersion.ForVendorPartition(ctx) } - if !sdkVersion.validateSystemSdk(ctx) { + if !sdkVersion.ValidateSystemSdk(ctx) { return sdkDep{} } - if sdkVersion.usePrebuilt(ctx) { - dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String()) + if sdkVersion.UsePrebuilt(ctx) { + dir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), sdkVersion.Kind.String()) jar := filepath.Join(dir, "android.jar") // There's no aidl for other SDKs yet. // TODO(77525052): Add aidl files for other SDKs too. - publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), "public") + publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.Version.String(), "public") aidl := filepath.Join(publicDir, "framework.aidl") jarPath := android.ExistentPathForSource(ctx, jar) aidlPath := android.ExistentPathForSource(ctx, aidl) @@ -380,23 +89,23 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() { return sdkDep{ invalidVersion: true, - bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.kind, sdkVersion.version.String())}, + bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.Version.String())}, } } if !jarPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, jar) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.Raw, jar) return sdkDep{} } if !aidlPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, aidl) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.Raw, aidl) return sdkDep{} } var systemModules string - if sdkVersion.defaultJavaLanguageVersion(ctx).usesJavaModules() { - systemModules = "sdk_public_" + sdkVersion.version.String() + "_system_modules" + if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() { + systemModules = "sdk_public_" + sdkVersion.Version.String() + "_system_modules" } return sdkDep{ @@ -418,8 +127,8 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep } } - switch sdkVersion.kind { - case sdkPrivate: + switch sdkVersion.Kind { + case android.SdkPrivate: return sdkDep{ useModule: true, systemModules: corePlatformSystemModules(ctx), @@ -427,8 +136,8 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep classpath: config.FrameworkLibraries, frameworkResModule: "framework-res", } - case sdkNone: - systemModules := sdkContext.systemModules() + case android.SdkNone: + systemModules := sdkContext.SystemModules() if systemModules == "" { ctx.PropertyErrorf("sdk_version", `system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`) @@ -444,34 +153,34 @@ func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep systemModules: systemModules, bootclasspath: []string{systemModules}, } - case sdkCorePlatform: + case android.SdkCorePlatform: return sdkDep{ useModule: true, systemModules: corePlatformSystemModules(ctx), bootclasspath: corePlatformBootclasspathLibraries(ctx), noFrameworksLibs: true, } - case sdkPublic: + case android.SdkPublic: return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) - case sdkSystem: + case android.SdkSystem: return toModule([]string{"android_system_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) - case sdkTest: + case android.SdkTest: return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) - case sdkCore: + case android.SdkCore: return sdkDep{ useModule: true, bootclasspath: []string{"core.current.stubs", config.DefaultLambdaStubsLibrary}, systemModules: "core-current-stubs-system-modules", noFrameworksLibs: true, } - case sdkModule: + case android.SdkModule: // TODO(146757305): provide .apk and .aidl that have more APIs for modules return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx)) - case sdkSystemServer: + case android.SdkSystemServer: // TODO(146757305): provide .apk and .aidl that have more APIs for modules return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) default: - panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw)) + panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw)) } } diff --git a/java/sdk_library.go b/java/sdk_library.go index e1ca77dcf..ebb21549f 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -814,22 +814,22 @@ func (c *commonToSdkLibraryAndImport) findClosestScopePath(scope *apiScope) *sco return nil } -func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { +func (c *commonToSdkLibraryAndImport) selectHeaderJarsForSdkVersion(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { // If a specific numeric version has been requested then use prebuilt versions of the sdk. - if sdkVersion.version.isNumbered() { + if sdkVersion.Version.IsNumbered() { return PrebuiltJars(ctx, c.moduleBase.BaseModuleName(), sdkVersion) } var apiScope *apiScope - switch sdkVersion.kind { - case sdkSystem: + switch sdkVersion.Kind { + case android.SdkSystem: apiScope = apiScopeSystem - case sdkModule: + case android.SdkModule: apiScope = apiScopeModuleLib - case sdkTest: + case android.SdkTest: apiScope = apiScopeTest - case sdkSystemServer: + case android.SdkSystemServer: apiScope = apiScopeSystemServer default: apiScope = apiScopePublic @@ -932,14 +932,14 @@ type SdkLibraryDependency interface { // // These are turbine generated jars so they only change if the externals of the // class changes but it does not contain and implementation or JavaDoc. - SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths + SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths // Get the implementation jars appropriate for the supplied sdk version. // // These are either the implementation jar for the whole sdk library or the implementation // jars for the stubs. The latter should only be needed when generating JavaDoc as otherwise // they are identical to the corresponding header jars. - SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths + SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths } type SdkLibrary struct { @@ -1147,7 +1147,7 @@ func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleCont return proptools.String(scopeProperties.Sdk_version) } - sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) + sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) if sdkDep.hasStandardLibs() { // If building against a standard sdk then use the sdk version appropriate for the scope. return apiScope.sdkVersion @@ -1465,17 +1465,17 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { mctx.CreateModule(sdkLibraryXmlFactory, &props) } -func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) android.Paths { - var ver sdkVersion - var kind sdkKind - if s.usePrebuilt(ctx) { - ver = s.version - kind = s.kind +func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s android.SdkSpec) android.Paths { + var ver android.SdkVersion + var kind android.SdkKind + if s.UsePrebuilt(ctx) { + ver = s.Version + kind = s.Kind } else { // We don't have prebuilt SDK for the specific sdkVersion. // Instead of breaking the build, fallback to use "system_current" - ver = sdkVersionCurrent - kind = sdkSystem + ver = android.SdkVersionCurrent + kind = android.SdkSystem } dir := filepath.Join("prebuilts", "sdk", ver.String(), kind.String()) @@ -1485,7 +1485,7 @@ func PrebuiltJars(ctx android.BaseModuleContext, baseName string, s sdkSpec) and if ctx.Config().AllowMissingDependencies() { return android.Paths{android.PathForSource(ctx, jar)} } else { - ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.raw, jar) + ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", s.Raw, jar) } return nil } @@ -1502,13 +1502,13 @@ func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) boo return len(otherApexInfo.InApexes) > 0 && reflect.DeepEqual(apexInfo.InApexes, otherApexInfo.InApexes) } -func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { +func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths { // If the client doesn't set sdk_version, but if this library prefers stubs over // the impl library, let's provide the widest API surface possible. To do so, // force override sdk_version to module_current so that the closest possible API // surface could be found in selectHeaderJarsForSdkVersion - if module.defaultsToStubs() && !sdkVersion.specified() { - sdkVersion = sdkSpecFrom("module_current") + if module.defaultsToStubs() && !sdkVersion.Specified() { + sdkVersion = android.SdkSpecFrom("module_current") } // Only provide access to the implementation library if it is actually built. @@ -1518,7 +1518,7 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkS // Only allow access to the implementation library in the following condition: // * No sdk_version specified on the referencing module. // * The referencing module is in the same apex as this. - if sdkVersion.kind == sdkPrivate || withinSameApexesAs(ctx, module) { + if sdkVersion.Kind == android.SdkPrivate || withinSameApexesAs(ctx, module) { if headerJars { return module.HeaderJars() } else { @@ -1531,12 +1531,12 @@ func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkS } // to satisfy SdkLibraryDependency interface -func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { +func (module *SdkLibrary) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { return module.sdkJars(ctx, sdkVersion, true /*headerJars*/) } // to satisfy SdkLibraryDependency interface -func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { +func (module *SdkLibrary) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { return module.sdkJars(ctx, sdkVersion, false /*headerJars*/) } @@ -1568,7 +1568,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont // If this builds against standard libraries (i.e. is not part of the core libraries) // then assume it provides both system and test apis. - sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) + sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) hasSystemAndTestApis := sdkDep.hasStandardLibs() module.sdkLibraryProperties.Generate_system_and_test_apis = hasSystemAndTestApis @@ -2069,7 +2069,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } } -func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths { +func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths { // For consistency with SdkLibrary make the implementation jar available to libraries that // are within the same APEX. @@ -2086,13 +2086,13 @@ func (module *SdkLibraryImport) sdkJars(ctx android.BaseModuleContext, sdkVersio } // to satisfy SdkLibraryDependency interface -func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { +func (module *SdkLibraryImport) SdkHeaderJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { // This module is just a wrapper for the prebuilt stubs. return module.sdkJars(ctx, sdkVersion, true) } // to satisfy SdkLibraryDependency interface -func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion sdkSpec) android.Paths { +func (module *SdkLibraryImport) SdkImplementationJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec) android.Paths { // This module is just a wrapper for the stubs. return module.sdkJars(ctx, sdkVersion, false) } diff --git a/java/sdk_test.go b/java/sdk_test.go index 028c4fe9a..2b1846592 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -313,10 +313,10 @@ func TestClasspath(t *testing.T) { checkClasspath := func(t *testing.T, result *android.TestResult, isJava8 bool) { foo := result.ModuleForTests("foo", variant) - javac := foo.Rule("javac").RelativeToTop() + javac := foo.Rule("javac") var deps []string - aidl := foo.MaybeRule("aidl").RelativeToTop() + aidl := foo.MaybeRule("aidl") if aidl.Rule != nil { deps = append(deps, android.PathRelativeToTop(aidl.Output)) } @@ -376,7 +376,7 @@ func TestClasspath(t *testing.T) { checkClasspath(t, result, true /* isJava8 */) if testcase.host != android.Host { - aidl := result.ModuleForTests("foo", variant).Rule("aidl").RelativeToTop() + aidl := result.ModuleForTests("foo", variant).Rule("aidl") android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.") } @@ -389,7 +389,7 @@ func TestClasspath(t *testing.T) { checkClasspath(t, result, false /* isJava8 */) if testcase.host != android.Host { - aidl := result.ModuleForTests("foo", variant).Rule("aidl").RelativeToTop() + aidl := result.ModuleForTests("foo", variant).Rule("aidl") android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.") } @@ -402,14 +402,16 @@ func TestClasspath(t *testing.T) { // Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 8 -target 8 t.Run("REL + Java language level 8", func(t *testing.T) { - result := fixtureFactory.Extend(prepareWithPlatformVersionRel).RunTestWithBp(t, bpJava8) + result := android.GroupFixturePreparers( + fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bpJava8) checkClasspath(t, result, true /* isJava8 */) }) // Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9 t.Run("REL + Java language level 9", func(t *testing.T) { - result := fixtureFactory.Extend(prepareWithPlatformVersionRel).RunTestWithBp(t, bp) + result := android.GroupFixturePreparers( + fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bp) checkClasspath(t, result, false /* isJava8 */) }) diff --git a/java/system_modules_test.go b/java/system_modules_test.go index 7d8935a4d..7b5a3867e 100644 --- a/java/system_modules_test.go +++ b/java/system_modules_test.go @@ -20,12 +20,12 @@ import ( "android/soong/android" ) -func getModuleHeaderJarsAsNormalizedPaths(result *android.TestResult, moduleNames ...string) []string { +func getModuleHeaderJarsAsRelativeToTopPaths(result *android.TestResult, moduleNames ...string) []string { paths := []string{} for _, moduleName := range moduleNames { module := result.Module(moduleName, "android_common") info := result.ModuleProvider(module, JavaInfoProvider).(JavaInfo) - paths = append(paths, result.NormalizePathsForTesting(info.HeaderJars)...) + paths = append(paths, info.HeaderJars.RelativeToTop().Strings()...) } return paths } @@ -50,15 +50,15 @@ var addSourceSystemModules = android.FixtureAddTextFile("source/Android.bp", ` `) func TestJavaSystemModules(t *testing.T) { - result := prepareForJavaTest.RunTest(t, addSourceSystemModules) + result := android.GroupFixturePreparers(prepareForJavaTest, addSourceSystemModules).RunTest(t) // check the existence of the source module sourceSystemModules := result.ModuleForTests("system-modules", "android_common") sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the source input modules. - expectedSourcePaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2") - android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs)) + expectedSourcePaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "system-module1", "system-module2") + android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, sourceInputs.RelativeToTop().Strings()) } var addPrebuiltSystemModules = android.FixtureAddTextFile("prebuilts/Android.bp", ` @@ -77,36 +77,37 @@ var addPrebuiltSystemModules = android.FixtureAddTextFile("prebuilts/Android.bp" `) func TestJavaSystemModulesImport(t *testing.T) { - result := prepareForJavaTest.RunTest(t, addPrebuiltSystemModules) + result := android.GroupFixturePreparers(prepareForJavaTest, addPrebuiltSystemModules).RunTest(t) // check the existence of the renamed prebuilt module prebuiltSystemModules := result.ModuleForTests("system-modules", "android_common") prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the renamed prebuilt input modules. - expectedPrebuiltPaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2") - android.AssertArrayString(t, "renamed prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs)) + expectedPrebuiltPaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "system-module1", "system-module2") + android.AssertArrayString(t, "renamed prebuilt system modules inputs", expectedPrebuiltPaths, prebuiltInputs.RelativeToTop().Strings()) } func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { - result := prepareForJavaTest.RunTest(t, + result := android.GroupFixturePreparers( + prepareForJavaTest, addSourceSystemModules, addPrebuiltSystemModules, - ) + ).RunTest(t) // check the existence of the source module sourceSystemModules := result.ModuleForTests("system-modules", "android_common") sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the source input modules. - expectedSourcePaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2") - android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs)) + expectedSourcePaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "system-module1", "system-module2") + android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, sourceInputs.RelativeToTop().Strings()) // check the existence of the renamed prebuilt module prebuiltSystemModules := result.ModuleForTests("prebuilt_system-modules", "android_common") prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the renamed prebuilt input modules. - expectedPrebuiltPaths := getModuleHeaderJarsAsNormalizedPaths(result, "prebuilt_system-module1", "prebuilt_system-module2") - android.AssertArrayString(t, "prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs)) + expectedPrebuiltPaths := getModuleHeaderJarsAsRelativeToTopPaths(result, "prebuilt_system-module1", "prebuilt_system-module2") + android.AssertArrayString(t, "prebuilt system modules inputs", expectedPrebuiltPaths, prebuiltInputs.RelativeToTop().Strings()) } diff --git a/java/testing.go b/java/testing.go index 221ceb118..80c107d12 100644 --- a/java/testing.go +++ b/java/testing.go @@ -160,28 +160,6 @@ func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.Fixtur ) } -func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) android.Config { - bp += GatherRequiredDepsForTest() - - mockFS := android.MockFS{} - - cc.GatherRequiredFilesForTest(mockFS) - - for k, v := range fs { - mockFS[k] = v - } - - if env == nil { - env = make(map[string]string) - } - if env["ANDROID_JAVA8_HOME"] == "" { - env["ANDROID_JAVA8_HOME"] = "jdk8" - } - config := android.TestArchConfig(buildDir, env, bp, mockFS) - - return config -} - func prebuiltApisFilesForLibs(apiLevels []string, sdkLibs []string) map[string][]byte { fs := make(map[string][]byte) for _, level := range apiLevels { @@ -200,19 +178,6 @@ func prebuiltApisFilesForLibs(apiLevels []string, sdkLibs []string) map[string][ return fs } -// Register build components provided by this package that are needed by tests. -// -// In particular this must register all the components that are used in the `Android.bp` snippet -// returned by GatherRequiredDepsForTest() -// -// deprecated: Use test fixtures instead, e.g. PrepareForTestWithJavaBuildComponents -func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { - registerRequiredBuildComponentsForTest(ctx) - - // Make sure that any tool related module types needed by dexpreopt have been registered. - dexpreopt.RegisterToolModulesForTest(ctx) -} - // registerRequiredBuildComponentsForTest registers the build components used by // PrepareForTestWithJavaDefaultModules. // @@ -228,7 +193,8 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterDexpreoptBootJarsComponents(ctx) RegisterDocsBuildComponents(ctx) RegisterGenRuleBuildComponents(ctx) - RegisterJavaBuildComponents(ctx) + registerJavaBuildComponents(ctx) + registerPlatformBootclasspathBuildComponents(ctx) RegisterPrebuiltApisBuildComponents(ctx) RegisterRuntimeResourceOverlayBuildComponents(ctx) RegisterSdkLibraryBuildComponents(ctx) @@ -236,23 +202,6 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterSystemModulesBuildComponents(ctx) } -// Gather the module definitions needed by tests that depend upon code from this package. -// -// Returns an `Android.bp` snippet that defines the modules that are needed by this package. -// -// deprecated: Use test fixtures instead, e.g. PrepareForTestWithJavaDefaultModules -func GatherRequiredDepsForTest() string { - bp := gatherRequiredDepsForTest() - - // For class loader context and <uses-library> tests. - bp += dexpreopt.CompatLibDefinitionsForTest() - - // Make sure that any tools needed for dexpreopting are defined. - bp += dexpreopt.BpToolModulesForTest() - - return bp -} - // gatherRequiredDepsForTest gathers the module definitions used by // PrepareForTestWithJavaDefaultModules. // diff --git a/python/binary.go b/python/binary.go index 5b0f080b3..e955492a6 100644 --- a/python/binary.go +++ b/python/binary.go @@ -36,8 +36,8 @@ func registerPythonBinaryComponents(ctx android.RegistrationContext) { type bazelPythonBinaryAttributes struct { Main string - Srcs bazel.LabelList - Data bazel.LabelList + Srcs bazel.LabelListAttribute + Data bazel.LabelListAttribute Python_version string } @@ -97,10 +97,13 @@ func PythonBinaryBp2Build(ctx android.TopDownMutatorContext) { // do nothing, since python_version defaults to PY3. } + srcs := android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs) + data := android.BazelLabelForModuleSrc(ctx, m.properties.Data) + attrs := &bazelPythonBinaryAttributes{ Main: main, - Srcs: android.BazelLabelForModuleSrcExcludes(ctx, m.properties.Srcs, m.properties.Exclude_srcs), - Data: android.BazelLabelForModuleSrc(ctx, m.properties.Data), + Srcs: bazel.MakeLabelListAttribute(srcs), + Data: bazel.MakeLabelListAttribute(data), Python_version: python_version, } diff --git a/rust/clippy_test.go b/rust/clippy_test.go index e90564f63..bd3bfb151 100644 --- a/rust/clippy_test.go +++ b/rust/clippy_test.go @@ -18,7 +18,6 @@ import ( "testing" "android/soong/android" - "android/soong/cc" ) func TestClippy(t *testing.T) { @@ -45,15 +44,6 @@ func TestClippy(t *testing.T) { clippy_lints: "none", }` - bp = bp + GatherRequiredDepsForTest() - bp = bp + cc.GatherRequiredDepsForTest(android.NoOsType) - - fs := map[string][]byte{ - // Reuse the same blueprint file for subdirectories. - "external/Android.bp": []byte(bp), - "hardware/Android.bp": []byte(bp), - } - var clippyLintTests = []struct { modulePath string fooFlags string @@ -66,29 +56,22 @@ func TestClippy(t *testing.T) { for _, tc := range clippyLintTests { t.Run("path="+tc.modulePath, func(t *testing.T) { - config := android.TestArchConfig(t.TempDir(), nil, bp, fs) - ctx := CreateTestContext(config) - ctx.Register() - _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) + result := android.GroupFixturePreparers( + prepareForRustTest, + // Test with the blueprint file in different directories. + android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), + ).RunTest(t) - r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - if r.Args["clippyFlags"] != tc.fooFlags { - t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["clippyFlags"], tc.fooFlags) - } + r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"]) - r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") - if r.Args["clippyFlags"] != "${config.ClippyDefaultLints}" { - t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["clippyFlags"], "${config.ClippyDefaultLints}") - } + r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"]) - r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") if r.Rule != nil { t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"]) } - }) } } diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 3ed086f20..c75276239 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -19,7 +19,6 @@ import ( "testing" "android/soong/android" - "android/soong/cc" ) // Test that feature flags are being correctly generated. @@ -132,15 +131,6 @@ func TestLints(t *testing.T) { lints: "none", }` - bp = bp + GatherRequiredDepsForTest() - bp = bp + cc.GatherRequiredDepsForTest(android.NoOsType) - - fs := map[string][]byte{ - // Reuse the same blueprint file for subdirectories. - "external/Android.bp": []byte(bp), - "hardware/Android.bp": []byte(bp), - } - var lintTests = []struct { modulePath string fooFlags string @@ -153,29 +143,20 @@ func TestLints(t *testing.T) { for _, tc := range lintTests { t.Run("path="+tc.modulePath, func(t *testing.T) { - config := android.TestArchConfig(t.TempDir(), nil, bp, fs) - ctx := CreateTestContext(config) - ctx.Register() - _, errs := ctx.ParseFileList(".", []string{tc.modulePath + "Android.bp"}) - android.FailIfErrored(t, errs) - _, errs = ctx.PrepareBuildActions(config) - android.FailIfErrored(t, errs) - - r := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - if !strings.Contains(r.Args["rustcFlags"], tc.fooFlags) { - t.Errorf("Incorrect flags for libfoo: %q, want %q", r.Args["rustcFlags"], tc.fooFlags) - } - - r = ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - if !strings.Contains(r.Args["rustcFlags"], "${config.RustDefaultLints}") { - t.Errorf("Incorrect flags for libbar: %q, want %q", r.Args["rustcFlags"], "${config.RustDefaultLints}") - } - - r = ctx.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") - if !strings.Contains(r.Args["rustcFlags"], "${config.RustAllowAllLints}") { - t.Errorf("Incorrect flags for libfoobar: %q, want %q", r.Args["rustcFlags"], "${config.RustAllowAllLints}") - } + result := android.GroupFixturePreparers( + prepareForRustTest, + // Test with the blueprint file in different directories. + android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), + ).RunTest(t) + + r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags) + + r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}") + r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}") }) } } diff --git a/rust/project_json_test.go b/rust/project_json_test.go index 7af463528..09d30dbde 100644 --- a/rust/project_json_test.go +++ b/rust/project_json_test.go @@ -28,9 +28,10 @@ import ( // testProjectJson run the generation of rust-project.json. It returns the raw // content of the generated file. func testProjectJson(t *testing.T, bp string) []byte { - result := prepareForRustTest. - Extend(android.FixtureMergeEnv(map[string]string{"SOONG_GEN_RUST_PROJECT": "1"})). - RunTestWithBp(t, bp) + result := android.GroupFixturePreparers( + prepareForRustTest, + android.FixtureMergeEnv(map[string]string{"SOONG_GEN_RUST_PROJECT": "1"}), + ).RunTestWithBp(t, bp) // The JSON file is generated via WriteFileToOutputDir. Therefore, it // won't appear in the Output of the TestingSingleton. Manually verify diff --git a/rust/testing.go b/rust/testing.go index 5be71c90e..75adcfce9 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -17,13 +17,12 @@ package rust import ( "android/soong/android" "android/soong/cc" - "android/soong/genrule" ) // Preparer that will define all cc module types and a limited set of mutators and singletons that // make those module types usable. var PrepareForTestWithRustBuildComponents = android.GroupFixturePreparers( - android.FixtureRegisterWithContext(RegisterRequiredBuildComponentsForTest), + android.FixtureRegisterWithContext(registerRequiredBuildComponentsForTest), ) // The directory in which rust test default modules will be defined. @@ -197,7 +196,7 @@ func GatherRequiredDepsForTest() string { return bp } -func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { +func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_binary", RustBinaryFactory) ctx.RegisterModuleType("rust_binary_host", RustBinaryHostFactory) ctx.RegisterModuleType("rust_bindgen", RustBindgenFactory) @@ -231,14 +230,3 @@ func RegisterRequiredBuildComponentsForTest(ctx android.RegistrationContext) { }) ctx.RegisterSingletonType("rust_project_generator", rustProjectGeneratorSingleton) } - -func CreateTestContext(config android.Config) *android.TestContext { - ctx := android.NewTestArchContext(config) - android.RegisterPrebuiltMutators(ctx) - ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators) - genrule.RegisterGenruleBuildComponents(ctx) - cc.RegisterRequiredBuildComponentsForTest(ctx) - RegisterRequiredBuildComponentsForTest(ctx) - - return ctx -} diff --git a/scripts/OWNERS b/scripts/OWNERS index 819808362..2b9c2ded9 100644 --- a/scripts/OWNERS +++ b/scripts/OWNERS @@ -3,3 +3,4 @@ per-file build-mainline-modules.sh = ngeoffray@google.com,paulduffin@google.com, per-file build-aml-prebuilts.sh = ngeoffray@google.com,paulduffin@google.com,mast@google.com per-file construct_context.py = ngeoffray@google.com,calin@google.com,mathieuc@google.com,skvadrik@google.com per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com +per-file gen_ndk*.sh = sophiez@google.com, allenhair@google.com diff --git a/scripts/build-mainline-modules.sh b/scripts/build-mainline-modules.sh index 18174a452..30cb93718 100755 --- a/scripts/build-mainline-modules.sh +++ b/scripts/build-mainline-modules.sh @@ -27,7 +27,6 @@ MODULES_SDK_AND_EXPORTS=( platform-mainline-test-exports runtime-module-host-exports runtime-module-sdk - stats-log-api-gen-exports statsd-module-sdk statsd-module-sdk-for-art tzdata-module-test-exports diff --git a/scripts/gen_ndk_usedby_apex.sh b/scripts/gen_ndk_usedby_apex.sh index f143161da..0d3ed5a29 100755 --- a/scripts/gen_ndk_usedby_apex.sh +++ b/scripts/gen_ndk_usedby_apex.sh @@ -33,7 +33,7 @@ parseReadelfOutput() { do if [[ $line = *FUNC*GLOBAL*UND*@* ]] ; then - echo "$line" | sed -r 's/.*UND (.*)@.*/\1/g' >> "$2" + echo "$line" | sed -r 's/.*UND (.*@.*)/\1/g' >> "$2" fi done < "$1" echo "" >> "$2" diff --git a/scripts/gen_sorted_bss_symbols.sh b/scripts/gen_sorted_bss_symbols.sh index 244ed0dea..a9b61a1ad 100755 --- a/scripts/gen_sorted_bss_symbols.sh +++ b/scripts/gen_sorted_bss_symbols.sh @@ -18,11 +18,11 @@ # their sizes. # Inputs: # Environment: -# CROSS_COMPILE: prefix added to nm tools +# CLANG_BIN: path to the clang bin directory # Arguments: # $1: Input ELF file # $2: Output symbol ordering file set -o pipefail -${CROSS_COMPILE}nm --size-sort $1 | awk '{if ($2 == "b" || $2 == "B") print $3}' > $2 +${CLANG_BIN}/llvm-nm --size-sort $1 | awk '{if ($2 == "b" || $2 == "B") print $3}' > $2 diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index 907f239cf..8168fbf6a 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -74,7 +74,7 @@ def parse_args(): return parser.parse_args() -def enforce_uses_libraries(manifest, required, optional, relax, is_apk = False): +def enforce_uses_libraries(manifest, required, optional, relax, is_apk, path): """Verify that the <uses-library> tags in the manifest match those provided by the build system. @@ -86,26 +86,36 @@ def enforce_uses_libraries(manifest, required, optional, relax, is_apk = False): is_apk: if the manifest comes from an APK or an XML file """ if is_apk: - manifest_required, manifest_optional = extract_uses_libs_apk(manifest) + manifest_required, manifest_optional, tags = extract_uses_libs_apk(manifest) else: - manifest_required, manifest_optional = extract_uses_libs_xml(manifest) - - err = [] - if manifest_required != required: - err.append('Expected required <uses-library> tags "%s", got "%s"' % - (', '.join(required), ', '.join(manifest_required))) - - if manifest_optional != optional: - err.append('Expected optional <uses-library> tags "%s", got "%s"' % - (', '.join(optional), ', '.join(manifest_optional))) - - if err: - errmsg = '\n'.join(err) - if not relax: - raise ManifestMismatchError(errmsg) - return errmsg - - return None + manifest_required, manifest_optional, tags = extract_uses_libs_xml(manifest) + + if manifest_required == required and manifest_optional == optional: + return None + + errmsg = ''.join([ + 'mismatch in the <uses-library> tags between the build system and the ' + 'manifest:\n', + '\t- required libraries in build system: [%s]\n' % ', '.join(required), + '\t vs. in the manifest: [%s]\n' % ', '.join(manifest_required), + '\t- optional libraries in build system: [%s]\n' % ', '.join(optional), + '\t vs. in the manifest: [%s]\n' % ', '.join(manifest_optional), + '\t- tags in the manifest (%s):\n' % path, + '\t\t%s\n' % '\t\t'.join(tags), + 'note: the following options are available:\n', + '\t- to temporarily disable the check on command line, rebuild with ', + 'RELAX_USES_LIBRARY_CHECK=true (this will set compiler filter "verify" ', + 'and disable AOT-compilation in dexpreopt)\n', + '\t- to temporarily disable the check for the whole product, set ', + 'PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true in the product makefiles\n', + '\t- to fix the check, make build system properties coherent with the ' + 'manifest\n', + '\t- see build/make/Changes.md for details\n']) + + if not relax: + raise ManifestMismatchError(errmsg) + + return errmsg def extract_uses_libs_apk(badging): @@ -115,14 +125,19 @@ def extract_uses_libs_apk(badging): required = [] optional = [] + lines = [] for match in re.finditer(pattern, badging): + lines.append(match.group(0)) libname = match.group(2) if match.group(1) == None: required.append(libname) else: optional.append(libname) - return first_unique_elements(required), first_unique_elements(optional) + required = first_unique_elements(required) + optional = first_unique_elements(optional) + tags = first_unique_elements(lines) + return required, optional, tags def extract_uses_libs_xml(xml): @@ -143,7 +158,15 @@ def extract_uses_libs_xml(xml): required = [uses_library_name(x) for x in libs if uses_library_required(x)] optional = [uses_library_name(x) for x in libs if not uses_library_required(x)] - return first_unique_elements(required), first_unique_elements(optional) + # render <uses-library> tags as XML for a pretty error message + tags = [] + for lib in libs: + tags.append(lib.toprettyxml()) + + required = first_unique_elements(required) + optional = first_unique_elements(optional) + tags = first_unique_elements(tags) + return required, optional, tags def first_unique_elements(l): @@ -278,7 +301,7 @@ def main(): # in the manifest. Raise an exception on mismatch, unless the script was # passed a special parameter to suppress exceptions. errmsg = enforce_uses_libraries(manifest, required, optional, - args.enforce_uses_libraries_relax, is_apk) + args.enforce_uses_libraries_relax, is_apk, args.input) # Create a status file that is empty on success, or contains an error # message on failure. When exceptions are suppressed, dexpreopt command diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py index 635ba9d1d..7159bdd74 100755 --- a/scripts/manifest_check_test.py +++ b/scripts/manifest_check_test.py @@ -49,9 +49,9 @@ class EnforceUsesLibrariesTest(unittest.TestCase): try: relax = False manifest_check.enforce_uses_libraries(doc, uses_libraries, - optional_uses_libraries, relax, is_apk=False) + optional_uses_libraries, relax, False, 'path/to/X/AndroidManifest.xml') manifest_check.enforce_uses_libraries(apk, uses_libraries, - optional_uses_libraries, relax, is_apk=True) + optional_uses_libraries, relax, True, 'path/to/X/X.apk') return True except manifest_check.ManifestMismatchError: return False diff --git a/scripts/toc.sh b/scripts/toc.sh index 8b1d25fb9..c6b78668c 100755 --- a/scripts/toc.sh +++ b/scripts/toc.sh @@ -17,7 +17,7 @@ # Script to handle generating a .toc file from a .so file # Inputs: # Environment: -# CROSS_COMPILE: prefix added to readelf tool +# CLANG_BIN: path to the clang bin directory # Arguments: # -i ${file}: input file (required) # -o ${file}: output file (required) @@ -35,34 +35,34 @@ EOF } do_elf() { - ("${CROSS_COMPILE}readelf" -d "${infile}" | grep SONAME || echo "No SONAME for ${infile}") > "${outfile}.tmp" - "${CROSS_COMPILE}readelf" --dyn-syms "${infile}" | awk '{$2=""; $3=""; print}' >> "${outfile}.tmp" + ("${CLANG_BIN}/llvm-readelf" -d "${infile}" | grep SONAME || echo "No SONAME for ${infile}") > "${outfile}.tmp" + "${CLANG_BIN}/llvm-readelf" --dyn-syms "${infile}" | awk '{$2=""; $3=""; print}' >> "${outfile}.tmp" cat <<EOF > "${depsfile}" ${outfile}: \\ - ${CROSS_COMPILE}readelf \\ + ${CLANG_BIN}/llvm-readelf \\ EOF } do_macho() { - "${CROSS_COMPILE}/otool" -l "${infile}" | grep LC_ID_DYLIB -A 5 > "${outfile}.tmp" - "${CROSS_COMPILE}/nm" -gP "${infile}" | cut -f1-2 -d" " | (grep -v 'U$' >> "${outfile}.tmp" || true) + "${CLANG_BIN}/llvm-objdump" -p "${infile}" | grep LC_ID_DYLIB -A 5 > "${outfile}.tmp" + "${CLANG_BIN}/llvm-nm" -gP "${infile}" | cut -f1-2 -d" " | (grep -v 'U$' >> "${outfile}.tmp" || true) cat <<EOF > "${depsfile}" ${outfile}: \\ - ${CROSS_COMPILE}/otool \\ - ${CROSS_COMPILE}/nm \\ + ${CLANG_BIN}/llvm-objdump \\ + ${CLANG_BIN}/llvm-nm \\ EOF } do_pe() { - "${CROSS_COMPILE}objdump" -x "${infile}" | grep "^Name" | cut -f3 -d" " > "${outfile}.tmp" - "${CROSS_COMPILE}nm" -g -f p "${infile}" | cut -f1-2 -d" " >> "${outfile}.tmp" + "${CLANG_BIN}/llvm-objdump" -x "${infile}" | grep "^Name" | cut -f3 -d" " > "${outfile}.tmp" + "${CLANG_BIN}/llvm-nm" -gP "${infile}" | cut -f1-2 -d" " >> "${outfile}.tmp" cat <<EOF > "${depsfile}" ${outfile}: \\ - ${CROSS_COMPILE}objdump \\ - ${CROSS_COMPILE}nm \\ + ${CLANG_BIN}/llvm-objdump \\ + ${CLANG_BIN}/llvm-nm \\ EOF } @@ -98,8 +98,8 @@ if [ -z "${depsfile:-}" ]; then usage fi -if [ -z "${CROSS_COMPILE:-}" ]; then - echo "CROSS_COMPILE environment variable must be set" +if [ -z "${CLANG_BIN:-}" ]; then + echo "CLANG_BIN environment variable must be set" usage fi @@ -107,7 +107,7 @@ rm -f "${outfile}.tmp" cat <<EOF > "${depsfile}" ${outfile}: \\ - ${CROSS_COMPILE}readelf \\ + ${CLANG_BIN}/llvm-readelf \\ EOF if [ -n "${elf:-}" ]; then diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index a886a18ce..b19fcc5cb 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -2407,6 +2407,7 @@ cc_prebuilt_library_shared { "1", "2", "3", + "current", ], }, arch: { @@ -2461,6 +2462,7 @@ cc_prebuilt_library_shared { "1", "2", "3", + "current", ], }, target: { @@ -2500,6 +2502,7 @@ cc_prebuilt_library_shared { "1", "2", "3", + "current", ], }, target: { diff --git a/sdk/testing.go b/sdk/testing.go index 44970f756..9465e136a 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -95,7 +95,10 @@ var PrepareForTestWithSdkBuildComponents = android.GroupFixturePreparers( func testSdkWithFs(t *testing.T, bp string, fs android.MockFS) *android.TestResult { t.Helper() - return prepareForSdkTest.RunTest(t, fs.AddToFixture(), android.FixtureWithRootAndroidBp(bp)) + return android.GroupFixturePreparers( + prepareForSdkTest, + fs.AddToFixture(), + ).RunTestWithBp(t, bp) } func testSdkError(t *testing.T, pattern, bp string) { diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 1ae557a8d..662338133 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -485,7 +485,7 @@ func ShTestHostFactory() android.Module { } type bazelShBinaryAttributes struct { - Srcs bazel.LabelList + Srcs bazel.LabelListAttribute // Bazel also supports the attributes below, but (so far) these are not required for Bionic // deps // data @@ -525,7 +525,8 @@ func ShBinaryBp2Build(ctx android.TopDownMutatorContext) { return } - srcs := android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src}) + srcs := bazel.MakeLabelListAttribute( + android.BazelLabelForModuleSrc(ctx, []string{*m.properties.Src})) attrs := &bazelShBinaryAttributes{ Srcs: srcs, diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index e9d905186..f42f9e902 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -371,6 +371,6 @@ func TestMinSdkVersionIsForwarded(t *testing.T) { android.AssertStringEquals(t, "min_sdk_version forwarding to cc module", "29", propFromCc) javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library) - propFromJava := javaModule.MinSdkVersion() + propFromJava := javaModule.MinSdkVersionString() android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava) } diff --git a/ui/build/bazel.go b/ui/build/bazel.go index ec561d540..0ebfcd804 100644 --- a/ui/build/bazel.go +++ b/ui/build/bazel.go @@ -149,6 +149,9 @@ func runBazel(ctx Context, config Config) { cmd.Args = append(cmd.Args, "--action_env=PATH="+pathEnvValue) } + // Allow Bazel actions to see the SHELL variable (passed to Bazel above) + cmd.Args = append(cmd.Args, "--action_env=SHELL") + // Append custom build flags to the Bazel command. Changes to these flags // may invalidate Bazel's analysis cache. // These should be appended as the final args, so that they take precedence. |