From d49e149f9058e6a66cd03b3f36d31042a688b2e2 Mon Sep 17 00:00:00 2001 From: Romain Jobredeaux Date: Tue, 14 Mar 2023 11:49:43 -0400 Subject: Create build settings and a transition to switch java/SDK versions The java toolchains will use selects based on the build settings to be properly configured based on sdk version and java version. The transition will be applied on all java/android/kotlin targets using wrappers. Change-Id: If52cf5fbe021e4298b36be7575d1c78fe2a932d7 Bug: 215230098 Test: Presubmits --- rules/common/BUILD.bazel | 3 + rules/common/api.bzl | 3 + rules/common/sdk_version.bzl | 65 +++++++++++++++++ rules/common/sdk_version_test.bzl | 150 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 221 insertions(+) create mode 100644 rules/common/sdk_version.bzl create mode 100644 rules/common/sdk_version_test.bzl (limited to 'rules/common') diff --git a/rules/common/BUILD.bazel b/rules/common/BUILD.bazel index e8ee30d3..e4988862 100644 --- a/rules/common/BUILD.bazel +++ b/rules/common/BUILD.bazel @@ -1,3 +1,6 @@ load(":api_test.bzl", "api_levels_test_suite") +load(":sdk_version_test.bzl", "sdk_version_test_suite") api_levels_test_suite(name = "api_test") + +sdk_version_test_suite(name = "sdk_version_test_suite") diff --git a/rules/common/api.bzl b/rules/common/api.bzl index 31fa964a..2547133e 100644 --- a/rules/common/api.bzl +++ b/rules/common/api.bzl @@ -20,6 +20,7 @@ load("@bazel_skylib//lib:dicts.bzl", "dicts") load("@soong_injection//api_levels:api_levels.bzl", "api_levels_released_versions") load("@soong_injection//product_config:product_variables.bzl", "product_vars") +_NONE_API_LEVEL_INT = -1 _PREVIEW_API_LEVEL_BASE = 9000 # Base constant for preview API levels. _FUTURE_API_LEVEL_INT = 10000 # API Level associated with an arbitrary future release @@ -118,6 +119,8 @@ def _default_app_target_sdk(): return _parse_api_level_from_version(codename) api = struct( + NONE_API_LEVEL = _NONE_API_LEVEL_INT, + FUTURE_API_LEVEL = _FUTURE_API_LEVEL_INT, is_preview = _is_preview, final_or_future = _final_or_future, default_app_target_sdk = _default_app_target_sdk, diff --git a/rules/common/sdk_version.bzl b/rules/common/sdk_version.bzl new file mode 100644 index 00000000..7b853762 --- /dev/null +++ b/rules/common/sdk_version.bzl @@ -0,0 +1,65 @@ +# Copyright (C) 2023 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. + +load("//build/bazel/rules/common:api.bzl", "api") + +# Only scopes that are available in prebuilts (and "none") are listed +# here for now, but the list should eventually match Soong's SdkKind +# enum. +ALL_KINDS = [ + "public", + "system", + "test", + "system_server", + "module", + "core", + "none", +] + +# Starlark implementation of SdkSpecFrom at https://cs.android.com/android/platform/build/soong/+/master:android/sdk_version.go;l=248-299;drc=69f4218c4feaeca953237cd9e76a9a8cc423d3e3. +def sdk_spec_from(sdk_version): + """Parses an sdk_version string into kind and api_level. + + Args: + sdk_version: a string to specify which SDK version to depend on. + - The empty string maps to the full set of private APIs and is currently unsupported. + - "core_platform" maps to the module scope of the core system modules. + - "none" maps to no SDK (used for bootstrapping the core). + - Otherwise, the format is "{kind}_{api_level}", where kind must be one of the strings + in ALL_KINDS, and api_level is either an integer, and android codename, or "current". + The default kind is "public", and can be omitted by simply providing "{api_level}". + + Returns: + A struct with a kind attribute set to one of the string in ALL_KINDS, and an api_level + attribute as returned by api.bzl's parse_api_level_from_version. + """ + if not sdk_version: + fail("Only prebuilt SDK versions are available, sdk_version must be specified and non-empty.") + if sdk_version == "core_platform": + fail("Only prebuilt SDK versions are available, sdk_version core_platform is not yet supported.") + if sdk_version == "none": + return struct(kind = "none", api_level = api.NONE_API_LEVEL) + if type(sdk_version) != type(""): + fail("sdk_version must be a string") + sep_index = sdk_version.rfind("_") + api_level_string = sdk_version if sep_index < 0 else sdk_version[sep_index + 1:] + api_level = api.parse_api_level_from_version(api_level_string) + kind = "public" if sep_index == -1 else sdk_version[:sep_index] + if kind not in ALL_KINDS: + fail("kind %s parsed from sdk_version %s must be one of %s" % ( + kind, + sdk_version, + ",".join(ALL_KINDS), + )) + return struct(kind = kind, api_level = api_level) diff --git a/rules/common/sdk_version_test.bzl b/rules/common/sdk_version_test.bzl new file mode 100644 index 00000000..f751fe2a --- /dev/null +++ b/rules/common/sdk_version_test.bzl @@ -0,0 +1,150 @@ +# Copyright (C) 2023 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. + +load("@bazel_skylib//lib:unittest.bzl", "analysistest", "asserts") +load("//build/bazel/rules/common:sdk_version.bzl", "sdk_spec_from") +load("//build/bazel/rules/common:api.bzl", "api") + +# Warning: this is a *lot* of boilerplate to test just one function. +# Scroll down to sdk_version_test_suite for the actual test cases. + +SdkSpec = provider() + +def _sdk_spec_from_tester_impl(ctx): + sdk_spec = sdk_spec_from(ctx.attr.sdk_version) + return [SdkSpec(kind = sdk_spec.kind, api_level = sdk_spec.api_level)] + +sdk_spec_from_tester = rule( + implementation = _sdk_spec_from_tester_impl, + attrs = { + "sdk_version": attr.string(), + }, +) + +def _sdk_spec_from_failure_test_impl(ctx): + env = analysistest.begin(ctx) + asserts.expect_failure(env, ctx.attr.expected_failure_message) + return analysistest.end(env) + +sdk_spec_from_failure_test = analysistest.make( + impl = _sdk_spec_from_failure_test_impl, + expect_failure = True, + attrs = {"expected_failure_message": attr.string()}, +) + +def test_sdk_spec_from_failure(name, sdk_version, expected_failure_message = ""): + sdk_spec_from_tester( + name = name + "_target", + sdk_version = sdk_version, + tags = ["manual"], + ) + sdk_spec_from_failure_test( + name = name, + target_under_test = name + "_target", + expected_failure_message = expected_failure_message, + ) + return name + +def _sdk_spec_from_output_test_impl(ctx): + env = analysistest.begin(ctx) + actual_sdk_spec = analysistest.target_under_test(env)[SdkSpec] + actual_kind = actual_sdk_spec.kind + asserts.equals( + env, + ctx.attr.expected_kind, + actual_kind, + "Expected kind %s, but got %s for sdk version %s" % ( + ctx.attr.expected_kind, + actual_kind, + ctx.attr.actual_sdk_version, + ), + ) + + actual_api_level = actual_sdk_spec.api_level + asserts.equals( + env, + ctx.attr.expected_api_level, + actual_api_level, + "Expected api_level %s, but got %s for sdk version %s" % ( + ctx.attr.expected_api_level, + actual_api_level, + ctx.attr.actual_sdk_version, + ), + ) + return analysistest.end(env) + +sdk_spec_from_output_test = analysistest.make( + impl = _sdk_spec_from_output_test_impl, + attrs = { + "actual_sdk_version": attr.string(), + "expected_kind": attr.string(), + "expected_api_level": attr.int(), + }, +) + +def test_sdk_spec_from_success(name, sdk_version, expected_kind, expected_api_level): + sdk_spec_from_tester( + name = name + "_target", + sdk_version = sdk_version, + tags = ["manual"], + ) + sdk_spec_from_output_test( + name = name, + target_under_test = name + "_target", + actual_sdk_version = sdk_version, + expected_kind = expected_kind, + expected_api_level = expected_api_level, + ) + return name + +def sdk_version_test_suite(name): + # sdk version expected to fail to parse. + failing_sdk_versions = [ + "malformed_malformed", + "malformed", + "", + "core_platform", + ] + failure_tests = [ + test_sdk_spec_from_failure( + name = sdk_version + "_failure_test", + sdk_version = sdk_version, + ) + for sdk_version in failing_sdk_versions + ] + + # Map of sdk_version to expected kind and api_level + sdk_version_to_kind_and_api_level = { + "current": ("public", api.FUTURE_API_LEVEL), + "core_current": ("core", api.FUTURE_API_LEVEL), + "Tiramisu": ("public", 33), + "33": ("public", 33), + "public_33": ("public", 33), + "none": ("none", api.NONE_API_LEVEL), + "system_Tiramisu": ("system", 33), + "system_32": ("system", 32), + } + success_tests = [ + test_sdk_spec_from_success( + name = sdk_version + "_success_test", + sdk_version = sdk_version, + expected_kind = sdk_version_to_kind_and_api_level[sdk_version][0], + expected_api_level = sdk_version_to_kind_and_api_level[sdk_version][1], + ) + for sdk_version in sdk_version_to_kind_and_api_level.keys() + ] + native.test_suite( + name = name, + tests = failure_tests + success_tests, + ) -- cgit v1.2.3