diff --git a/contrib/BUILD b/contrib/BUILD new file mode 100644 index 000000000..e69de29bb diff --git a/contrib/androidsdk_repository_alias/BUILD.bazel b/contrib/androidsdk_repository_alias/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/contrib/androidsdk_repository_alias/BUILD.bazel.template b/contrib/androidsdk_repository_alias/BUILD.bazel.template new file mode 100644 index 000000000..325e5e5d8 --- /dev/null +++ b/contrib/androidsdk_repository_alias/BUILD.bazel.template @@ -0,0 +1,136 @@ +load( + ":rule.bzl", + "android_sdk_alias", + "android_sdk_toolchain_alias", + "android_tool_alias", + "filegroup_alias", + "java_binary_alias", + "java_import_alias", +) + +package(default_visibility = ["//visibility:public"]) + +toolchain_type(name = "sdk_toolchain_type") + +android_sdk_alias( + name = "sdk", +) + + +android_sdk_toolchain_alias( + name = "sdk-toolchain", +) + +android_tool_alias( + name = "aapt", + tool_name = "aapt", +) + +android_tool_alias( + name = "aapt2", + tool_name = "aapt2", +) + +android_tool_alias( + name = "adb", + tool_name = "adb", +) + +android_tool_alias( + name = "aidl", + tool_name = "aidl", +) + +java_binary_alias( + name = "apksigner", + target_name = "apk_signer", +) + +java_binary_alias( + name = "dx", + target_name = "dx", +) + +android_tool_alias( + name = "zipalign", + tool_name = "zip_align", +) + +alias( + name = "zipalign_binary", + actual = ":zipalign", +) + +android_tool_alias( + name = "main_dex_list_creator", + tool_name = "main_dex_list_creator", +) + +java_binary_alias( + name = "legacy_main_dex_list_generator", + target_name = "legacy_main_dex_list_generator", +) + +android_tool_alias( + name = "proguard", + tool_name = "proguard", +) + +java_import_alias( + name = "core-for-system-modules-jar", + target_name = "core_for_system_modules_jar", +) + +java_import_alias( + name = "org_apache_http_legacy", + target_name = "org_apache_http_legacy", +) + +config_setting( + name = "windows", + constraint_values = ["@platforms//os:windows"], +) + +genrule( + name = "generate_fail_sh", + outs = ["fail.sh"], + cmd = "echo -e '#!/bin/bash\\\\nexit 1' >> $@; chmod +x $@", + executable = True, +) + +sh_binary( + name = "bash_fail", + srcs = [":generate_fail_sh"], +) + +genrule( + name = "generate_fail_cmd", + outs = ["fail.cmd"], + cmd = "echo @exit /b 1 > $@", + executable = True, +) + +sh_binary( + name = "windows_fail", + srcs = [":generate_fail_cmd"], +) + +alias( + name = "fail", + actual = select({ + ":windows": ":windows_fail", + "//conditions:default": ":bash_fail", + }), +) + +filegroup_alias( + name = "sdk_path", + target_name = "sdk_path", +) + +filegroup_alias( + name = "files", + target_name = "files", +) + + diff --git a/contrib/androidsdk_repository_alias/androidsdk_repository_alias.bzl b/contrib/androidsdk_repository_alias/androidsdk_repository_alias.bzl new file mode 100644 index 000000000..8eb8b840a --- /dev/null +++ b/contrib/androidsdk_repository_alias/androidsdk_repository_alias.bzl @@ -0,0 +1,14 @@ +"""androidsdk_repository_alias rule. + +Shim rule to access the configured androidsdk for the current platform under a known name. +Usefule to be backwards compatible with current usages of @androidsdk// +""" + +def _android_sdk_repository_alias_impl(repo_ctx): + repo_ctx.symlink(Label(":rule.bzl.template"), "rule.bzl") + repo_ctx.symlink(Label(":BUILD.bazel.template"), "BUILD.bazel") + return None + +androidsdk_repository_alias = repository_rule( + implementation = _android_sdk_repository_alias_impl, +) diff --git a/contrib/androidsdk_repository_alias/rule.bzl.template b/contrib/androidsdk_repository_alias/rule.bzl.template new file mode 100644 index 000000000..cc16a98ef --- /dev/null +++ b/contrib/androidsdk_repository_alias/rule.bzl.template @@ -0,0 +1,160 @@ +def _androidsdk_alias_impl(ctx): + """An experimental implementation of androidsdk using toolchain resolution.""" + toolchain = ctx.toolchains[":sdk_toolchain_type"] + return [ + toolchain, + toolchain.android_sdk_info, + toolchain.android_sdk_targets_info, + ] + +android_sdk_alias = rule( + implementation = _androidsdk_alias_impl, + toolchains = [":sdk_toolchain_type"], +) + + +def _androidsdk_toolchain_alias_impl(ctx): + """An experimental implementation of androidsdk using toolchain resolution.""" + return [ + ctx.toolchains[":sdk_toolchain_type"], + ] + +android_sdk_toolchain_alias = rule( + implementation = _androidsdk_toolchain_alias_impl, + toolchains = [":sdk_toolchain_type"], +) + +RUNFILES_SUPPORT_HEADER = """ +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \ +source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ +source "$0.runfiles/$f" 2>/dev/null || \ +source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ +source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ +{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e +# --- end runfiles.bash initialization v3 --- +""" + +def _android_tool_alias_impl(ctx): + toolchain = ctx.toolchains[":sdk_toolchain_type"] + targets_info = toolchain.android_sdk_targets_info + tool_name = ctx.attr.tool_name + field_name = tool_name + tool_target = getattr(targets_info, field_name) + + print(tool_target) + runfiles = getattr(tool_target, "default_runfiles", ctx.runfiles()) + + executable = tool_target.files_to_run.executable + + # Native tools that need a wrapper script to set LD_LIBRARY_PATH + if tool_name in ["aapt", "aapt2", "aidl", "zipalign"]: + rlocation_tool_path = "{}/build-tools/{}/{}".format( + executable.owner.workspace_name, + targets_info.build_tools_version, + tool_name, + ) + script_content = """#!/bin/bash +set -e +{runfiles_header} +BUILD_TOOLS_DIR="$(dirname "$(rlocation "{tool_path}")")" +tool="${{BUILD_TOOLS_DIR}}/{tool_name}" +exec env LD_LIBRARY_PATH="${{BUILD_TOOLS_DIR}}/lib64" "${{tool}}" "$@" +""".format( + runfiles_header = RUNFILES_SUPPORT_HEADER, + tool_path = rlocation_tool_path, + tool_name = tool_name, + ) + ctx.actions.write( + output = ctx.outputs.executable, + content = script_content, + is_executable = True, + ) + else: + # For other tools, create a symlink to the original executable. + ctx.actions.symlink( + output = ctx.outputs.executable, + target_file = executable, + ) + + return [ + DefaultInfo( + executable = ctx.outputs.executable, + runfiles = runfiles, + ), + ] + +android_tool_alias = rule( + implementation = _android_tool_alias_impl, + attrs = { + "tool_name": attr.string(mandatory = True), + "_sh_runfiles": attr.label(default = "@bazel_tools//tools/bash/runfiles"), + }, + toolchains = [":sdk_toolchain_type"], + executable = True, +) + +def _java_import_alias_impl(ctx): + toolchain = ctx.toolchains[":sdk_toolchain_type"] + targets_info = toolchain.android_sdk_targets_info + target = getattr(targets_info, ctx.attr.target_name) + return [ + DefaultInfo(files = target[DefaultInfo].files), + target[JavaInfo], + ] + +java_import_alias = rule( + implementation = _java_import_alias_impl, + attrs = { + "target_name": attr.string(mandatory = True), + }, + toolchains = [":sdk_toolchain_type"], +) + +def _java_binary_alias_impl(ctx): + toolchain = ctx.toolchains[":sdk_toolchain_type"] + targets_info = toolchain.android_sdk_targets_info + target = getattr(targets_info, ctx.attr.target_name) + + executable = target.files_to_run.executable + + ctx.actions.symlink( + output = ctx.outputs.executable, + target_file = executable, + ) + + return [ + DefaultInfo( + executable = ctx.outputs.executable, + files = target[DefaultInfo].files, + runfiles = target[DefaultInfo].default_runfiles, + ), + target[JavaInfo], + ] + +java_binary_alias = rule( + implementation = _java_binary_alias_impl, + attrs = { + "target_name": attr.string(mandatory = True), + }, + toolchains = [":sdk_toolchain_type"], + executable = True, +) + +def _filegroup_alias_impl(ctx): + toolchain = ctx.toolchains[":sdk_toolchain_type"] + targets_info = toolchain.android_sdk_targets_info + target = getattr(targets_info, ctx.attr.target_name) + return [ + DefaultInfo(files = target[DefaultInfo].files), + ] + +filegroup_alias = rule( + implementation = _filegroup_alias_impl, + attrs = { + "target_name": attr.string(mandatory = True), + }, + toolchains = [":sdk_toolchain_type"], +) diff --git a/contrib/remote_android_sdk_repository/BUILD.bazel b/contrib/remote_android_sdk_repository/BUILD.bazel new file mode 100644 index 000000000..e69de29bb diff --git a/contrib/remote_android_sdk_repository/helper.bzl b/contrib/remote_android_sdk_repository/helper.bzl new file mode 100644 index 000000000..63af45420 --- /dev/null +++ b/contrib/remote_android_sdk_repository/helper.bzl @@ -0,0 +1,595 @@ +load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS") +load("@rules_android//rules:rules.bzl", "android_sdk") +load("@rules_java//java:defs.bzl", "java_binary", "java_import") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") + +RUNFILES_SUPPORT_HEADER = """ +# --- begin runfiles.bash initialization v3 --- +# Copy-pasted from the Bazel Bash runfiles library v3. +set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash +echo "$$0" +echo "$$0" +echo "$$0" +source "$${RUNFILES_DIR:-/dev/null}/$$f" 2>/dev/null || \ +source "$$(grep -sm1 "^$$f " "$${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \ +source "$$0.runfiles/$$f" 2>/dev/null || \ +source "$$(grep -sm1 "^$$f " "$$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ +source "$$(grep -sm1 "^$$f " "$$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \ +{ echo>&2 "ERROR: cannot find $$f"; exit 1; }; f=; set -e + # --- end runfiles.bash initialization v3 --- +""" + +def _bool_flag_impl(_unused_ctx): + pass + +_bool_flag = rule( + implementation = _bool_flag_impl, + build_setting = config.bool(flag = True), +) + +def _int_flag_impl(ctx): + allowed_values = ctx.attr.values + value = ctx.build_setting_value + if len(allowed_values) != 0 and value not in ctx.attr.values: + fail( + "Error setting %s: invalid value '%d'. Allowed values are %s" % ( + ctx.label, + value, + ",".join([str(val) for val in allowed_values]), + ), + ) + +int_flag = rule( + implementation = _int_flag_impl, + build_setting = config.int(flag = True), + attrs = { + "values": attr.int_list( + doc = "The list of allowed values for this setting. An error is raised if any other value is given.", + ), + }, + doc = "An int-typed build setting that can be set on the command line", +) + +def _create_config_setting_rule(): + """Create config_setting rule for windows. + + These represent the matching --host_cpu values. + """ + name = "windows" + if not native.existing_rule(name): + native.config_setting( + name = name, + constraint_values = ["@platforms//os:windows"], + ) + + native.config_setting( + name = "d8_standalone_dexer", + values = {"define": "android_standalone_dexing_tool=d8_compat_dx"}, + ) + + native.config_setting( + name = "dx_standalone_dexer", + values = {"define": "android_standalone_dexing_tool=dx_compat_dx"}, + ) + + _bool_flag( + name = "allow_proguard", + build_setting_default = True, + ) + + native.config_setting( + name = "disallow_proguard", + flag_values = {":allow_proguard": "false"}, + ) + +def create_android_sdk_rules( + name, + build_tools_version, + build_tools_directory, + api_levels, + default_api_level, + exec_compatible_with = None): + """Generate android_sdk rules for the API levels in the Android SDK. + + Args: + name: string, the name of the repository being generated. + build_tools_version: string, the version of Android's build tools to use. + build_tools_directory: string, the directory name of the build tools in + sdk's build-tools directory. + api_levels: list of ints, the API levels from which to get android.jar + et al. and create android_sdk rules. + default_api_level: int, the API level to alias the default sdk to if + --android_sdk is not specified on the command line. + """ + + _create_config_setting_rule() + + int_flag( + name = "api_level", + build_setting_default = default_api_level, + values = api_levels, + visibility = ["//visibility:public"], + ) + + windows_only_files = [ + "build-tools/%s/aapt.exe" % build_tools_directory, + "build-tools/%s/aidl.exe" % build_tools_directory, + "build-tools/%s/zipalign.exe" % build_tools_directory, + "platform-tools/adb.exe", + ] + native.glob( + [ + "build-tools/%s/aapt2.exe" % build_tools_directory, + "build-tools/%s/dexdump.exe" % build_tools_directory, + ], + allow_empty = True, + ) + + linux_only_files = [ + "build-tools/%s/aapt" % build_tools_directory, + "build-tools/%s/aidl" % build_tools_directory, + "build-tools/%s/zipalign" % build_tools_directory, + "platform-tools/adb", + ] + native.glob( + [ + "extras", + "build-tools/%s/aapt2" % build_tools_directory, + "build-tools/%s/dexdump" % build_tools_directory, + ], + allow_empty = True, + exclude_directories = 0, + ) + + # This filegroup is used to pass the minimal contents of the SDK to the + # Android integration tests. Note that in order to work on Windows, we cannot + # include directories and must keep the size small. + build_tools_major_version = int(build_tools_version.split(".")[0]) + native.filegroup( + name = "files", + srcs = ( + [ + "build-tools/%s/lib/dx.jar" % build_tools_directory, + "build-tools/%s/mainDexClasses.rules" % build_tools_directory, + ] if build_tools_major_version <= 30 else [] + ) + + [ + "build-tools/%s/lib/apksigner.jar" % build_tools_directory, + "build-tools/%s/lib/d8.jar" % build_tools_directory, + ":build_tools_libs", + ] + [ + "platforms/android-%d/%s" % (api_level, filename) + for api_level in api_levels + for filename in ["android.jar", "core-for-system-modules.jar", "framework.aidl"] + ] + select({ + ":windows": windows_only_files, + "//conditions:default": linux_only_files, + }), + ) + + for api_level in api_levels: + if api_level >= 23: + # Android 23 removed most of org.apache.http from android.jar and moved it + # to a separate jar. + java_import( + name = "org_apache_http_legacy-%d" % api_level, + jars = ["platforms/android-%d/optional/org.apache.http.legacy.jar" % api_level], + ) + + if api_level >= 28: + # Android 28 removed most of android.test from android.jar and moved it + # to separate jars. + java_import( + name = "legacy_test-%d" % api_level, + jars = [ + "platforms/android-%d/optional/android.test.base.jar" % api_level, + "platforms/android-%d/optional/android.test.mock.jar" % api_level, + "platforms/android-%d/optional/android.test.runner.jar" % api_level, + ], + neverlink = 1, + ) + + native.config_setting( + name = "api_%d_enabled" % api_level, + flag_values = { + ":api_level": str(api_level), + }, + ) + + android_sdk( + name = "sdk-%d" % api_level, + aapt = select({ + ":windows": "build-tools/%s/aapt.exe" % build_tools_directory, + "//conditions:default": ":aapt_binary", + }), + aapt2 = select({ + ":windows": "build-tools/%s/aapt2.exe" % build_tools_directory, + "//conditions:default": ":aapt2_binary", + }), + adb = select({ + ":windows": "platform-tools/adb.exe", + "//conditions:default": "platform-tools/adb", + }), + aidl = select({ + ":windows": "build-tools/%s/aidl.exe" % build_tools_directory, + "//conditions:default": ":aidl_binary", + }), + android_jar = "platforms/android-%d/android.jar" % api_level, + apksigner = ":apksigner", + build_tools_version = build_tools_version, + dx = select({ + "d8_standalone_dexer": ":d8_compat_dx", + "dx_standalone_dexer": ":dx_binary", + "//conditions:default": ":d8_compat_dx", + }), + framework_aidl = "platforms/android-%d/framework.aidl" % api_level, + legacy_main_dex_list_generator = ":generate_main_dex_list", + main_dex_classes = "build-tools/%s/mainDexClasses.rules" % build_tools_directory, + main_dex_list_creator = ":main_dex_list_creator", + proguard = select({ + ":disallow_proguard": ":fail", + "//conditions:default": "@remote_java_tools//:proguard", + }), + # See https://github.com/bazelbuild/bazel/issues/8757 + tags = ["__ANDROID_RULES_MIGRATION__"], + zipalign = select({ + ":windows": "build-tools/%s/zipalign.exe" % build_tools_directory, + "//conditions:default": ":zipalign_binary", + }), + core_for_system_modules_jar = ":core-for-system-modules-jar", + org_apache_http_legacy = ":org_apache_http_legacy", + sdk_path = ":sdk_path", + files = ":files", + ) + + native.toolchain( + name = "sdk-%d-toolchain" % api_level, + toolchain = ":sdk-%d" % api_level, + toolchain_type = "@androidsdk//:sdk_toolchain_type", + target_settings = [ + ":api_%d_enabled" % api_level, + ], + exec_compatible_with = exec_compatible_with or HOST_CONSTRAINTS, + visibility = ["//visibility:public"], + ) + + create_dummy_sdk_toolchain() + + native.alias( + name = "org_apache_http_legacy", + actual = ":org_apache_http_legacy-%d" % default_api_level, + ) + + sdk_alias_dict = { + "//conditions:default": "sdk-%d" % default_api_level, + } + + for api_level in api_levels: + sdk_alias_dict[":api_%d_enabled" % api_level] = "sdk-%d" % api_level + + native.alias( + name = "sdk", + actual = select( + sdk_alias_dict, + no_match_error = "Unknown Android SDK level, valid levels are %s" % ",".join([str(level) for level in api_levels]), + ), + ) + + native.alias( + name = "sdk-toolchain", + actual = ":sdk-%d-toolchain" % default_api_level, + ) + + java_import( + name = "core-for-system-modules-jar", + jars = ["platforms/android-%d/core-for-system-modules.jar" % default_api_level], + ) + + java_binary( + name = "apksigner", + main_class = "com.android.apksigner.ApkSignerTool", + runtime_deps = ["build-tools/%s/lib/apksigner.jar" % build_tools_directory], + ) + + native.filegroup( + name = "build_tools_libs", + srcs = native.glob([ + "build-tools/%s/lib/**" % build_tools_directory, + # Build tools version 24.0.0 added a lib64 folder. + "build-tools/%s/lib64/**" % build_tools_directory, + ], allow_empty = True), + ) + + for tool in ["aapt2", "aidl", "zipalign"]: + native.genrule( + name = tool + "_runner", + srcs = [], + outs = [tool + "_runner.sh"], + cmd = "\n".join([ + "cat > $@ << 'EOF'", + "#!/usr/bin/env bash", + RUNFILES_SUPPORT_HEADER, + # The tools under build-tools/VERSION require the libraries under + # build-tools/VERSION/lib, so we can't simply depend on them as a + # file like we do with aapt. + # On Windows however we can use these binaries directly because + # there's no runfiles support so Bazel just creates a junction to + # {SDK}/build-tools. + "env", + "SDK=$${0}.runfiles/%s" % name, + # If $${SDK} is not a directory, it means that this tool is running + # from a runfiles directory, in the case of + # android_instrumentation_test. Hence, use the androidsdk + # that's already present in the runfiles of the current context. + "if [[ ! -d $${SDK} ]] ; then", + " SDK=$$(pwd)/../%s" % name, + "fi", + "tool=$${SDK}/build-tools/%s/%s" % (build_tools_directory, tool), + "exec env LD_LIBRARY_PATH=$${SDK}/build-tools/%s/lib64 $$tool $$*" % build_tools_directory, + "EOF\n", + ]), + ) + + sh_binary( + name = tool + "_binary", + srcs = [tool + "_runner.sh"], + data = [ + ":build_tools_libs", + "build-tools/%s/%s" % (build_tools_directory, tool), + ], + deps = ["@bazel_tools//tools/bash/runfiles"], + ) + + # For the default Android toolchain //toolchains/android:android_default + native.alias( + name = "aapt2", + actual = select({ + ":windows": "build-tools/%s/aapt2.exe" % build_tools_directory, + "//conditions:default": ":aapt2_binary", + }), + ) + + native.alias( + name = "fail", + actual = select({ + ":windows": ":windows_fail.cmd", + "//conditions:default": ":bash_fail", + }), + ) + + sh_binary( + name = "bash_fail", + srcs = [":generate_fail_sh"], + ) + + native.genrule( + name = "generate_fail_sh", + outs = ["fail.sh"], + cmd = "echo -e '#!/bin/bash\\nexit 1' >> $@; chmod +x $@", + executable = 1, + ) + + sh_binary( + name = "windows_fail.cmd", + srcs = [":generate_fail_cmd"], + ) + + native.genrule( + name = "generate_fail_cmd", + outs = ["fail.cmd"], + cmd = "echo @exit /b 1 > $@", + executable = 1, + ) + + native.genrule( + name = "dx_binary_source", + srcs = [], + outs = ["dx_binary.sh"], + cmd = "\n".join([ + "cat > $@ <<'EOF'", + "#!/bin/bash", + "", + "echo dx_binary should not be used anymore.", + "exit 1", + "", + "EOF\n", + ]), + ) + + native.genrule( + name = "main_dex_list_creator_source", + srcs = [], + outs = ["main_dex_list_creator.sh"], + cmd = "\n".join([ + "cat > $@ <<'EOF'", + "#!/bin/bash", + "", + "echo main_dex_list_creator should not be used anymore.", + "exit 1", + "", + "EOF\n", + ]), + ) + + sh_binary( + name = "main_dex_list_creator", + srcs = ["main_dex_list_creator.sh"], + ) + sh_binary( + name = "dx_binary", + srcs = [":dx_binary_source"], + ) + java_binary( + name = "generate_main_dex_list", + jvm_flags = [ + "-XX:+TieredCompilation", + "-XX:TieredStopAtLevel=1", + # Consistent with what we use for desugar. + "-Xms8g", + "-Xmx8g", + ], + main_class = "com.android.tools.r8.GenerateMainDexList", + runtime_deps = ["@rules_android//src/tools/java/com/google/devtools/build/android/r8"], + ) + java_binary( + name = "d8_compat_dx", + main_class = "com.google.devtools.build.android.r8.CompatDx", + runtime_deps = [ + "@rules_android//src/tools/java/com/google/devtools/build/android/r8", + ], + ) + native.alias( + name = "d8_jar_import", + actual = ":fail", + ) + +TAGDIR_TO_TAG_MAP = { + "google_apis_playstore": "playstore", + "google_apis": "google", + "default": "android", + "android-tv": "tv", + "android-wear": "wear", +} + +ARCHDIR_TO_ARCH_MAP = { + "x86": "x86", + "armeabi-v7a": "arm", +} + +# buildifier: disable=unnamed-macro +def create_system_images_filegroups(system_image_dirs): + """Generate filegroups for the system images in the Android SDK. + + Args: + system_image_dirs: list of strings, the directories containing system image + files to be used to create android_device rules. + """ + + # These images will need to be updated as Android releases new system images. + # We are intentionally not adding future releases because there is no + # guarantee that they will work out of the box. Supported system images should + # be added here once they have been confirmed to work with the Bazel Android + # testing infrastructure. + system_images = [ + (tag, str(api), arch) + for tag in ["android", "google"] + for api in [10] + list(range(15, 20)) + list(range(21, 30)) + for arch in ("x86", "arm") + ] + [ + ("playstore", str(api), "x86") + for api in list(range(24, 30)) + ] + tv_images = [ + ("tv", str(api), "x86") + for api in range(21, 30) + ] + [ + ("tv", "21", "arm"), + ("tv", "23", "arm"), + ] + wear_images = [ + ("wear", str(api), "x86") + for api in [23, 25, 26, 28] + ] + [ + ("wear", str(api), "arm") + for api in [23, 25] + ] + supported_system_images = system_images + tv_images + wear_images + + installed_system_images_dirs = {} + for system_image_dir in system_image_dirs: + apidir, tagdir, archdir = system_image_dir.split("/")[1:] + if "-" not in apidir: + continue + api = apidir.split("-")[1] # "android-24" --> "24", "android-O" --> "O" + if tagdir not in TAGDIR_TO_TAG_MAP: + continue + tag = TAGDIR_TO_TAG_MAP[tagdir] + if archdir not in ARCHDIR_TO_ARCH_MAP: + continue + arch = ARCHDIR_TO_ARCH_MAP[archdir] + if (tag, api, arch) in supported_system_images: + name = "emulator_images_%s_%s_%s" % (tag, api, arch) + installed_system_images_dirs[name] = system_image_dir + else: + # TODO(bazel-team): If the user has an unsupported system image installed, + # should we print a warning? This includes all 64-bit system-images. + pass + + for (tag, api, arch) in supported_system_images: + name = "emulator_images_%s_%s_%s" % (tag, api, arch) + if name in installed_system_images_dirs: + system_image_dir = installed_system_images_dirs[name] + + # For supported system images that exist in /sdk/system-images/, we + # create a filegroup with their contents. + native.filegroup( + name = name, + srcs = native.glob([ + "%s/**" % system_image_dir, + ]), + ) + native.filegroup( + name = "%s_qemu2_extra" % name, + srcs = native.glob(["%s/kernel-ranchu" % system_image_dir], allow_empty = True), + ) + else: + # For supported system images that are not installed in the SDK, we + # create a "poison pill" genrule to display a helpful error message to + # a user who attempts to run a test against an android_device that + # they don't have the system image for installed. + native.genrule( + name = name, + outs = [ + # Necessary so that the build doesn't fail in analysis because + # android_device expects a file named source.properties. + "poison_pill_for_%s/source.properties" % name, + ], + cmd = """echo \ + This rule requires that the Android SDK used by Bazel has the \ + following system image installed: %s. Please install this system \ + image through the Android SDK Manager and try again. ; \ + exit 1 + """ % name, + ) + native.filegroup( + name = "%s_qemu2_extra" % name, + srcs = [], + ) # buildifier: disable=unnamed-macro + +# This is a dummy sdk toolchain that matches any platform. It will +# fail if actually resolved to and used. +# buildifier: disable=unnamed-macro +def create_dummy_sdk_toolchain(): + "Create a dummy SDK for fallback builds" + + native.toolchain( + name = "sdk-dummy-toolchain", + toolchain = ":sdk-dummy", + toolchain_type = ":sdk_toolchain_type", + ) + + native.filegroup(name = "jar-filegroup", srcs = ["dummy.jar"]) + + native.genrule( + name = "genrule", + srcs = [], + outs = ["empty.sh"], + cmd = "echo '' >> \"$@\"", + executable = 1, + ) + + sh_binary(name = "empty-binary", srcs = [":genrule"]) + + android_sdk( + name = "sdk-dummy", + aapt = ":empty-binary", + adb = ":empty-binary", + aidl = ":empty-binary", + android_jar = ":jar-filegroup", + apksigner = ":empty-binary", + dx = ":empty-binary", + framework_aidl = "dummy.jar", + main_dex_classes = "dummy.jar", + main_dex_list_creator = ":empty-binary", + proguard = ":empty-binary", + tags = ["__ANDROID_RULES_MIGRATION__"], + zipalign = ":empty-binary", + ) diff --git a/contrib/remote_android_sdk_repository/remote_android_sdk_repository.bzl b/contrib/remote_android_sdk_repository/remote_android_sdk_repository.bzl new file mode 100644 index 000000000..fd21da0aa --- /dev/null +++ b/contrib/remote_android_sdk_repository/remote_android_sdk_repository.bzl @@ -0,0 +1,92 @@ +"""Rules for importing the Android SDK from http archive. + +Rule remote_android_sdk_repository imports an SDK and creates toolchain definitions for it. +""" + +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +_SDK_REPO_TEMPLATE = Label(":template.bzl") + +_BUILD_TOOLS_DIR = "build-tools" +_PLATFORMS_DIR = "platforms" +_SYSTEM_IMAGES_DIR = "system-images" + +_SDK_DIRS = { + "build_tools": _BUILD_TOOLS_DIR, + "cmdline_tools": "cmdline-tools", + "emulator": "emulator", + "ndk": "ndk", + "platform_tools": "platform-tools", + "platforms": _PLATFORMS_DIR, +} + +def _remote_android_sdk_repository_impl(repo_ctx): + for attr_name, output_dir in _SDK_DIRS.items(): + attr_value = struct(**getattr(repo_ctx.attr, attr_name)) + + repo_ctx.download_and_extract( + url = attr_value.url, + sha256 = attr_value.sha256, + output = output_dir + "/" + attr_value.add_prefix, + stripPrefix = attr_value.strip_prefix, + ) + + repo_ctx.symlink(Label(":helper.bzl"), "helper.bzl") + repo_ctx.template( + "BUILD.bazel", + _SDK_REPO_TEMPLATE, + substitutions = { + "__repository_name__": repo_ctx.name, + "__build_tools_version__": repo_ctx.attr.build_tools_version, + "__build_tools_directory__": repo_ctx.attr.build_tools_version, + "__api_levels__": str(repo_ctx.attr.api_level), + "__default_api_level__": str(repo_ctx.attr.api_level), + "__system_image_dirs__": "", + "__exec_compatible_with__": ",".join(["\"{}\"".format(platform) for platform in repo_ctx.attr.exec_compatible_with]), + }, + ) + return None + +_remote_android_sdk_repository = repository_rule( + implementation = _remote_android_sdk_repository_impl, + attrs = { + "api_level": attr.int(default = 0), + "build_tools_version": attr.string(), + "build_tools": attr.string_dict(mandatory = True), + "cmdline_tools": attr.string_dict(mandatory = True), + "platforms": attr.string_dict(mandatory = True), + "platform_tools": attr.string_dict(mandatory = True), + "emulator": attr.string_dict(mandatory = True), + "ndk": attr.string_dict(mandatory = True), + "exec_compatible_with": attr.string_list(), + }, +) + +# And here we define an extra repository androidsdk that contains the alias + +def remote_android_sdk_repository(name, sdk): + """Imports an Android SDK from a http archive and creates runtime toolchain definitions for it. + + Register the toolchains defined by this macro via `register_toolchains("@//:all")`, where + `` is the value of the `name` parameter. + + Toolchain resolution is determined with exec_compatible_with parameter. + + Args: + name: A unique name for this rule. + sdk: Android SDK configuration. + """ + _remote_android_sdk_repository( + name = name, + api_level = sdk["api_level"], + build_tools_version = sdk["build_tools_version"], + build_tools = sdk["build_tools"], + cmdline_tools = sdk["cmdline_tools"], + platforms = sdk["platforms"], + platform_tools = sdk["platform_tools"], + ndk = sdk["ndk"], + emulator = sdk["emulator"], + exec_compatible_with = sdk["exec_compatible_with"], + ) + native.register_toolchains("@%s//:sdk-toolchain" % name) + native.register_toolchains("@%s//:all" % name) diff --git a/contrib/remote_android_sdk_repository/repositories.bzl b/contrib/remote_android_sdk_repository/repositories.bzl new file mode 100644 index 000000000..d34958348 --- /dev/null +++ b/contrib/remote_android_sdk_repository/repositories.bzl @@ -0,0 +1,48 @@ +"""Utility functions to configure Android SDKs.""" + +load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") +load("//contrib/androidsdk_repository_alias:androidsdk_repository_alias.bzl", "androidsdk_repository_alias") +load(":remote_android_sdk_repository.bzl", "remote_android_sdk_repository") + +def sdk_package(url, sha256, add_prefix = "", strip_prefix = ""): + return dict( + url = url, + sha256 = sha256, + add_prefix = add_prefix, + strip_prefix = strip_prefix, + ) + +def remote_android_sdk( + name, + api_level, + build_tools_version, + exec_compatible_with, + build_tools, + cmdline_tools, + platforms, + platform_tools, + emulator, + ndk): + return dict( + name = name, + api_level = api_level, + build_tools_version = build_tools_version, + build_tools = build_tools, + exec_compatible_with = exec_compatible_with, + cmdline_tools = cmdline_tools, + platforms = platforms, + platform_tools = platform_tools, + emulator = emulator, + ndk = ndk, + ) + +def register_android_sdks(sdks): + for item in sdks: + maybe( + remote_android_sdk_repository, + name = item["name"], + sdk = item, + ) + + # Repo for backwards compatibility with usages of @androisdk + androidsdk_repository_alias(name = "androidsdk") diff --git a/contrib/remote_android_sdk_repository/template.bzl b/contrib/remote_android_sdk_repository/template.bzl new file mode 100644 index 000000000..d587bc595 --- /dev/null +++ b/contrib/remote_android_sdk_repository/template.bzl @@ -0,0 +1,137 @@ +load( + ":helper.bzl", + "create_android_sdk_rules", + "create_system_images_filegroups", +) + +package(default_visibility = ["//visibility:public"]) + +# The toolchain type used to distinguish Android SDK toolchains. +toolchain_type(name = "sdk_toolchain_type") + +config_feature_flag( + name = "true", + allowed_values = [ + "true", + "false", + ], + default_value = "true", +) + +config_setting( + name = "always_true", + flag_values = { + ":true": "true", + }, +) + +config_setting( + name = "always_false", + flag_values = { + ":true": "false", + }, +) + +config_setting( + name = "darwin_arm64", + constraint_values = [ + "@platforms//os:macos", + "@platforms//cpu:arm64", + ], + visibility = ["//visibility:public"], +) + +config_setting( + name = "darwin_x86_64", + constraint_values = [ + "@platforms//os:macos", + "@platforms//cpu:x86_64", + ], + visibility = ["//visibility:public"], +) + +alias( + name = "has_androidsdk", + actual = ":always_true", +) + +create_android_sdk_rules( + name = "__repository_name__", + build_tools_version = "__build_tools_version__", + build_tools_directory = "__build_tools_directory__", + api_levels = [__api_levels__], + default_api_level = __default_api_level__, + exec_compatible_with = [__exec_compatible_with__], +) + +alias( + name = "adb", + actual = "platform-tools/adb", +) + +alias( + name = "dexdump", + actual = "build-tools/%s/dexdump" % "__build_tools_directory__", +) + +alias( + name = "emulator", + actual = "emulator/emulator", +) + +# emulator v29+ removed the arm and x86 specific binaries. +# Keeping these aliases around for backwards compatibility. +alias( + name = "emulator_arm", + actual = "emulator/emulator", +) + +alias( + name = "emulator_x86", + actual = "emulator/emulator", +) + +filegroup( + name = "emulator_x86_bios", + srcs = glob( + ["emulator/lib/pc-bios/*"], + allow_empty = True, + ), +) + +alias( + name = "mksd", + actual = "emulator/mksdcard", +) + +filegroup( + name = "emulator_shared_libs", + srcs = glob( + ["emulator/lib64/**"], + allow_empty = True, + ), +) + +filegroup( + name = "sdk_path", + srcs = ["."], +) + +filegroup( + name = "qemu2_x86", + srcs = ["emulator/emulator"] + select({ + ":darwin_x86_64": ["emulator/qemu/darwin-x86_64/qemu-system-i386"], + ":darwin_arm64": ["emulator/qemu/darwin-aarch64/qemu-system-aarch64"], + "//conditions:default": ["emulator/qemu/linux-x86_64/qemu-system-i386"], + }), +) + +create_system_images_filegroups( + system_image_dirs = [__system_image_dirs__], +) + +exports_files( + # TODO(katre): implement these. + #[ __exported_files__] + + glob(["system-images/**"], allow_empty = True), +) diff --git a/contrib/rules.bzl b/contrib/rules.bzl new file mode 100644 index 000000000..0f345a0b9 --- /dev/null +++ b/contrib/rules.bzl @@ -0,0 +1,12 @@ +"""Starlark rules from external contributors for building Android apps.""" + +load( + "//contrib/remote_android_sdk_repository:repositories.bzl", + _register_android_sdks = "register_android_sdks", + _remote_android_sdk = "remote_android_sdk", + _sdk_package = "sdk_package", +) + +register_android_sdks = _register_android_sdks +remote_android_sdk = _remote_android_sdk +sdk_package = _sdk_package diff --git a/providers/providers.bzl b/providers/providers.bzl index 935aae188..dda084106 100644 --- a/providers/providers.bzl +++ b/providers/providers.bzl @@ -477,6 +477,35 @@ AndroidSdkInfo, _AndroidSdkInfo_raw = provider( ), ) +# buildifier: disable=name-conventions +AndroidSdkTargetsInfo = provider( + doc = "Provides targets from the Android SDK.", + fields = dict( + build_tools_version = "String, the version of the build tools.", + framework_aidl = "Target for the framework aidl.", + aidl_lib = "Target for the aidl lib.", + android_jar = "Target for the android jar.", + source_properties = "Target for the source properties.", + shrinked_android_jar = "Target for the shrinked android jar.", + main_dex_classes = "Target for the main dex classes.", + adb = "Target for adb.", + dx = "Target for dx.", + main_dex_list_creator = "Target for the main dex list creator.", + aidl = "Target for aidl.", + aapt = "Target for aapt.", + aapt2 = "Target for aapt2.", + apk_builder = "Target for apk builder.", + apk_signer = "Target for apk signer.", + proguard = "Target for proguard.", + legacy_main_dex_list_generator = "Target for legacy main dex list generator.", + zip_align = "Target for zipalign.", + core_for_system_modules_jar = "Target for core-for-system-modules.jar.", + org_apache_http_legacy = "Target for org_apache_http_legacy.", + sdk_path = "Target for the sdk_path filegroup.", + files = "Target for the files filegroup.", + ), +) + # See b/419287003 for more details of why this provider is needed. AndroidLocalizedFilesInfo = provider( doc = "AndroidLocalizedFilesInfo", diff --git a/rules/android_sdk.bzl b/rules/android_sdk.bzl index e490cbb97..e05c7c303 100644 --- a/rules/android_sdk.bzl +++ b/rules/android_sdk.bzl @@ -13,7 +13,11 @@ # limitations under the License. """Bazel rule for Android sdk.""" -load("//providers:providers.bzl", "AndroidSdkInfo") +load( + "//providers:providers.bzl", + "AndroidSdkInfo", + "AndroidSdkTargetsInfo", +) load("//rules:visibility.bzl", "PROJECT_VISIBILITY") load(":attrs.bzl", "ANDROID_SDK_ATTRS") @@ -42,6 +46,35 @@ def _impl(ctx): system = None, legacy_main_dex_list_generator = ctx.attr.legacy_main_dex_list_generator.files_to_run if ctx.attr.legacy_main_dex_list_generator else None, ) + android_sdk_targets_info = AndroidSdkTargetsInfo( + build_tools_version = ctx.attr.build_tools_version, + framework_aidl = ctx.attr.framework_aidl, + android_jar = ctx.attr.android_jar, + source_properties = ctx.attr.source_properties, + main_dex_classes = ctx.attr.main_dex_classes, + adb = ctx.attr.adb, + dx = ctx.attr.dx, + main_dex_list_creator = ctx.attr.main_dex_list_creator, + aidl = ctx.attr.aidl, + aapt = ctx.attr.aapt, + aapt2 = ctx.attr.aapt2, + apk_builder = ctx.attr.apkbuilder, + apk_signer = ctx.attr.apksigner, + proguard = proguard, + zip_align = ctx.attr.zipalign, + legacy_main_dex_list_generator = ctx.attr.legacy_main_dex_list_generator, + core_for_system_modules_jar = ctx.attr.core_for_system_modules_jar, + org_apache_http_legacy = ctx.attr.org_apache_http_legacy, + sdk_path = ctx.attr.sdk_path, + files = ctx.attr.files, + ) + return [ + android_sdk_info, + android_sdk_targets_info, + platform_common.ToolchainInfo( + android_sdk_info = android_sdk_info, + android_sdk_targets_info = android_sdk_targets_info, + ), return [ android_sdk_info, platform_common.ToolchainInfo(android_sdk_info = android_sdk_info), diff --git a/rules/attrs.bzl b/rules/attrs.bzl index 5115b069e..49fc6f9a6 100644 --- a/rules/attrs.bzl +++ b/rules/attrs.bzl @@ -256,6 +256,22 @@ ANDROID_BINARY_ATTRS = _add( incremental_dexing = _tristate.create( default = _tristate.auto, ), + sdk_path = attr.label( + allow_files = True, + cfg = "exec", + ), + files = attr.label( + allow_files = True, + cfg = "exec", + ), + core_for_system_modules_jar = attr.label( + allow_single_file = [".jar"], + cfg = "exec", + ), + org_apache_http_legacy = attr.label( + allow_files = True, + cfg = "exec", + ), inline_constants = attr.bool( default = False, ), diff --git a/toolchains/android/toolchain.bzl b/toolchains/android/toolchain.bzl index 98dd0f32a..84cb73ea4 100644 --- a/toolchains/android/toolchain.bzl +++ b/toolchains/android/toolchain.bzl @@ -52,7 +52,7 @@ _ATTRS = dict( adb = attr.label( allow_files = True, cfg = "exec", - default = "@androidsdk//:platform-tools/adb", + default = "@androidsdk//:adb", executable = True, ), add_g3itr_xslt = attr.label(