aboutsummaryrefslogtreecommitdiff
path: root/rules/common
diff options
context:
space:
mode:
authorRomain Jobredeaux <jobredeaux@google.com>2023-03-14 11:49:43 -0400
committerRomain Jobredeaux <jobredeaux@google.com>2023-04-03 14:51:48 -0400
commitd49e149f9058e6a66cd03b3f36d31042a688b2e2 (patch)
treec8637c5b49a74a1ca65329702b1cdea8a58dc204 /rules/common
parent0b6438cc5235a1406da505572d6ea20024d1b9ab (diff)
downloadbazel-d49e149f9058e6a66cd03b3f36d31042a688b2e2.tar.gz
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
Diffstat (limited to 'rules/common')
-rw-r--r--rules/common/BUILD.bazel3
-rw-r--r--rules/common/api.bzl3
-rw-r--r--rules/common/sdk_version.bzl65
-rw-r--r--rules/common/sdk_version_test.bzl150
4 files changed, 221 insertions, 0 deletions
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,
+ )