Vendor dependencies
Let's see how I like this workflow.
This commit is contained in:
parent
34d1830413
commit
9c435dc440
7500 changed files with 1665121 additions and 99 deletions
109
vendor/cxx/tools/buck/prelude/android/aapt2_link.bzl
vendored
Normal file
109
vendor/cxx/tools/buck/prelude/android/aapt2_link.bzl
vendored
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "Aapt2LinkInfo")
|
||||
|
||||
BASE_PACKAGE_ID = 0x7f
|
||||
|
||||
def get_aapt2_link(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
aapt2_compile_rules: ["artifact"],
|
||||
android_manifest: "artifact",
|
||||
includes_vector_drawables: bool.type = False,
|
||||
no_auto_version: bool.type = False,
|
||||
no_version_transitions: bool.type = False,
|
||||
no_auto_add_overlay: bool.type = False,
|
||||
use_proto_format: bool.type = False,
|
||||
no_resource_removal: bool.type = False,
|
||||
should_keep_raw_values: bool.type = False,
|
||||
package_id_offset: int.type = 0,
|
||||
resource_stable_ids: ["artifact", None] = None,
|
||||
preferred_density: [str.type, None] = None,
|
||||
min_sdk: [int.type, None] = None,
|
||||
filter_locales: bool.type = False,
|
||||
locales: [str.type] = [],
|
||||
compiled_resource_apks: ["artifact"] = [],
|
||||
additional_aapt2_params: [str.type] = [],
|
||||
extra_filtered_resources: [str.type] = []) -> Aapt2LinkInfo.type:
|
||||
aapt2_command = cmd_args(android_toolchain.aapt2)
|
||||
aapt2_command.add("link")
|
||||
|
||||
# aapt2 only supports @ for -R or input files, not for all args, so we pass in all "normal"
|
||||
# args here.
|
||||
resources_apk = ctx.actions.declare_output("resource-apk.ap_")
|
||||
aapt2_command.add(["-o", resources_apk.as_output()])
|
||||
proguard_config = ctx.actions.declare_output("proguard_config.pro")
|
||||
aapt2_command.add(["--proguard", proguard_config.as_output()])
|
||||
|
||||
# We don't need the R.java output, but aapt2 won't output R.txt unless we also request R.java.
|
||||
r_dot_java = ctx.actions.declare_output("initial-rdotjava")
|
||||
aapt2_command.add(["--java", r_dot_java.as_output()])
|
||||
r_dot_txt = ctx.actions.declare_output("R.txt")
|
||||
aapt2_command.add(["--output-text-symbols", r_dot_txt.as_output()])
|
||||
|
||||
aapt2_command.add(["--manifest", android_manifest])
|
||||
aapt2_command.add(["-I", android_toolchain.android_jar])
|
||||
|
||||
if includes_vector_drawables:
|
||||
aapt2_command.add("--no-version-vectors")
|
||||
if no_auto_version:
|
||||
aapt2_command.add("--no-auto-version")
|
||||
if no_version_transitions:
|
||||
aapt2_command.add("--no-version-transitions")
|
||||
if not no_auto_add_overlay:
|
||||
aapt2_command.add("--auto-add-overlay")
|
||||
if use_proto_format:
|
||||
aapt2_command.add("--proto-format")
|
||||
if no_resource_removal:
|
||||
aapt2_command.add("--no-resource-removal")
|
||||
if should_keep_raw_values:
|
||||
aapt2_command.add("--keep-raw-values")
|
||||
if package_id_offset != 0:
|
||||
aapt2_command.add(["--package-id", "0x{}".format(BASE_PACKAGE_ID + package_id_offset)])
|
||||
if resource_stable_ids != None:
|
||||
aapt2_command.add(["--stable-ids", resource_stable_ids])
|
||||
if preferred_density != None:
|
||||
aapt2_command.add(["--preferred-density", preferred_density])
|
||||
if min_sdk != None:
|
||||
aapt2_command.add(["--min-sdk-version", min_sdk])
|
||||
if filter_locales and len(locales) > 0:
|
||||
aapt2_command.add("-c")
|
||||
|
||||
# "NONE" means "en", update the list of locales
|
||||
aapt2_command.add(cmd_args([locale if locale != "NONE" else "en" for locale in locales], delimiter = ","))
|
||||
|
||||
for compiled_resource_apk in compiled_resource_apks:
|
||||
aapt2_command.add(["-I", compiled_resource_apk])
|
||||
|
||||
aapt2_compile_rules_args_file = ctx.actions.write("aapt2_compile_rules_args_file", cmd_args(aapt2_compile_rules, delimiter = " "))
|
||||
aapt2_command.add("-R")
|
||||
aapt2_command.add(cmd_args(aapt2_compile_rules_args_file, format = "@{}"))
|
||||
aapt2_command.hidden(aapt2_compile_rules)
|
||||
|
||||
aapt2_command.add(additional_aapt2_params)
|
||||
|
||||
ctx.actions.run(aapt2_command, category = "aapt2_link")
|
||||
|
||||
# The normal resource filtering apparatus is super slow, because it extracts the whole apk,
|
||||
# strips files out of it, then repackages it.
|
||||
#
|
||||
# This is a faster filtering step that just uses zip -d to remove entries from the archive.
|
||||
# It's also superbly dangerous.
|
||||
if len(extra_filtered_resources) > 0:
|
||||
filter_resources_cmd = cmd_args()
|
||||
filter_resources_cmd.add(["zip", "-d"])
|
||||
filter_resources_cmd.add(resources_apk)
|
||||
filter_resources_cmd.add(extra_filtered_resources)
|
||||
|
||||
ctx.actions.run(filter_resources_cmd, category = "aapt2_filter_resources")
|
||||
|
||||
return Aapt2LinkInfo(
|
||||
primary_resources_apk = resources_apk,
|
||||
proguard_config_file = proguard_config,
|
||||
r_dot_txt = r_dot_txt,
|
||||
)
|
||||
208
vendor/cxx/tools/buck/prelude/android/android.bzl
vendored
Normal file
208
vendor/cxx/tools/buck/prelude/android/android.bzl
vendored
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "AaptMode", "DuplicateResourceBehaviour", "TargetCpuType")
|
||||
load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo")
|
||||
load("@prelude//java:java.bzl", "dex_min_sdk_version", "select_java_test_toolchain")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaPlatformInfo", "JavaTestToolchainInfo", "JavaToolchainInfo")
|
||||
load("@prelude//kotlin:kotlin_toolchain.bzl", "KotlinToolchainInfo")
|
||||
load("@prelude//genrule.bzl", "genrule_attributes")
|
||||
load(":android_apk.bzl", "android_apk_impl")
|
||||
load(":android_build_config.bzl", "android_build_config_impl")
|
||||
load(":android_instrumentation_apk.bzl", "android_instrumentation_apk_impl")
|
||||
load(":android_instrumentation_test.bzl", "android_instrumentation_test_impl")
|
||||
load(":android_library.bzl", "android_library_impl")
|
||||
load(":android_manifest.bzl", "android_manifest_impl")
|
||||
load(":android_prebuilt_aar.bzl", "android_prebuilt_aar_impl")
|
||||
load(":android_resource.bzl", "android_resource_impl")
|
||||
load(":android_toolchain.bzl", "AndroidPlatformInfo", "AndroidToolchainInfo")
|
||||
load(":apk_genrule.bzl", "apk_genrule_impl")
|
||||
load(":configuration.bzl", "cpu_split_transition", "cpu_split_transition_instrumentation_test_apk", "cpu_transition", "do_not_build_only_native_code_transition", "is_building_android_binary_attr")
|
||||
load(":gen_aidl.bzl", "gen_aidl_impl")
|
||||
load(":prebuilt_native_library.bzl", "prebuilt_native_library_impl")
|
||||
load(":robolectric_test.bzl", "robolectric_test_impl")
|
||||
load(":voltron.bzl", "android_app_modularity_impl")
|
||||
|
||||
def android_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:android",
|
||||
providers = [
|
||||
AndroidPlatformInfo,
|
||||
AndroidToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def _dex_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:dex_for_android",
|
||||
providers = [
|
||||
DexToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def java_toolchain_for_android():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:java_for_android",
|
||||
providers = [
|
||||
JavaPlatformInfo,
|
||||
JavaToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def _kotlin_toolchain():
|
||||
return attrs.toolchain_dep(
|
||||
# FIXME: prelude// should be standalone (not refer to fbcode//)
|
||||
default = "fbcode//buck2/platform/toolchain:kotlin",
|
||||
providers = [
|
||||
KotlinToolchainInfo,
|
||||
],
|
||||
)
|
||||
|
||||
def is_build_only_native_code():
|
||||
return select(
|
||||
{
|
||||
"DEFAULT": False,
|
||||
"fbsource//xplat/buck2/platform/android:build_only_native_code": True,
|
||||
},
|
||||
)
|
||||
|
||||
implemented_rules = {
|
||||
"android_app_modularity": android_app_modularity_impl,
|
||||
"android_binary": android_apk_impl,
|
||||
"android_build_config": android_build_config_impl,
|
||||
"android_instrumentation_apk": android_instrumentation_apk_impl,
|
||||
"android_instrumentation_test": android_instrumentation_test_impl,
|
||||
"android_library": android_library_impl,
|
||||
"android_manifest": android_manifest_impl,
|
||||
"android_prebuilt_aar": android_prebuilt_aar_impl,
|
||||
"android_resource": android_resource_impl,
|
||||
"apk_genrule": apk_genrule_impl,
|
||||
"gen_aidl": gen_aidl_impl,
|
||||
"prebuilt_native_library": prebuilt_native_library_impl,
|
||||
"robolectric_test": robolectric_test_impl,
|
||||
}
|
||||
|
||||
# Can't load `read_bool` here because it will cause circular load.
|
||||
DISABLE_SPLIT_TRANSITIONS = read_config("buck2", "android_td_disable_transitions_hack") in ("True", "true")
|
||||
|
||||
def _transition_dep_wrapper(split_transition_dep, transition_dep):
|
||||
if DISABLE_SPLIT_TRANSITIONS:
|
||||
return transition_dep
|
||||
return split_transition_dep
|
||||
|
||||
extra_attributes = {
|
||||
"android_aar": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
},
|
||||
"android_app_modularity": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
},
|
||||
"android_binary": {
|
||||
"aapt_mode": attrs.enum(AaptMode, default = "aapt1"), # Match default in V1
|
||||
"application_module_configs": attrs.dict(key = attrs.string(), value = attrs.list(attrs.transition_dep(cfg = cpu_transition)), sorted = False, default = {}),
|
||||
"build_config_values_file": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"deps": attrs.list(_transition_dep_wrapper(split_transition_dep = attrs.split_transition_dep(cfg = cpu_split_transition), transition_dep = attrs.transition_dep(cfg = cpu_transition)), default = []),
|
||||
"dex_tool": attrs.string(default = "d8"), # Match default in V1
|
||||
"duplicate_resource_behavior": attrs.enum(DuplicateResourceBehaviour, default = "allow_by_default"), # Match default in V1
|
||||
"manifest": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"min_sdk_version": attrs.option(attrs.int(), default = None),
|
||||
"module_manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"_android_installer": attrs.default_only(attrs.label(
|
||||
# FIXME: prelude// should be standalone (not refer to buck//)
|
||||
default = "buck//src/com/facebook/buck/installer/android:android_installer",
|
||||
)),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = True)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_build_config": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_is_building_android_binary": is_building_android_binary_attr(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_instrumentation_apk": {
|
||||
"aapt_mode": attrs.enum(AaptMode, default = "aapt1"), # Match default in V1
|
||||
"apk": attrs.transition_dep(cfg = do_not_build_only_native_code_transition),
|
||||
"cpu_filters": attrs.list(attrs.enum(TargetCpuType), default = []),
|
||||
"deps": attrs.list(_transition_dep_wrapper(split_transition_dep = attrs.split_transition_dep(cfg = cpu_split_transition_instrumentation_test_apk), transition_dep = attrs.transition_dep(cfg = cpu_transition)), default = []),
|
||||
"dex_tool": attrs.string(default = "d8"), # Match default in V1
|
||||
"manifest": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"manifest_skeleton": attrs.option(attrs.one_of(attrs.transition_dep(cfg = cpu_transition), attrs.source()), default = None),
|
||||
"min_sdk_version": attrs.option(attrs.int(), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = True)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_instrumentation_test": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_library": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_dex_min_sdk_version": attrs.default_only(attrs.option(attrs.int(), default = dex_min_sdk_version())),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_is_building_android_binary": is_building_android_binary_attr(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
"_kotlin_toolchain": _kotlin_toolchain(),
|
||||
},
|
||||
"android_manifest": {
|
||||
"_android_toolchain": android_toolchain(),
|
||||
},
|
||||
"android_prebuilt_aar": {
|
||||
# Prebuilt jars are quick to build, and often contain third-party code, which in turn is
|
||||
# often a source of annotations and constants. To ease migration to ABI generation from
|
||||
# source without deps, we have them present during ABI gen by default.
|
||||
"required_for_source_only_abi": attrs.bool(default = True),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
"_dex_min_sdk_version": attrs.default_only(attrs.option(attrs.int(), default = dex_min_sdk_version())),
|
||||
"_dex_toolchain": _dex_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"android_resource": {
|
||||
"assets": attrs.option(attrs.one_of(attrs.source(allow_directory = True), attrs.dict(key = attrs.string(), value = attrs.source(), sorted = True)), default = None),
|
||||
"project_assets": attrs.option(attrs.source(allow_directory = True), default = None),
|
||||
"project_res": attrs.option(attrs.source(allow_directory = True), default = None),
|
||||
"res": attrs.option(attrs.one_of(attrs.source(allow_directory = True), attrs.dict(key = attrs.string(), value = attrs.source(), sorted = True)), default = None),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_build_only_native_code": attrs.default_only(attrs.bool(default = is_build_only_native_code())),
|
||||
},
|
||||
"apk_genrule": genrule_attributes() | {
|
||||
"type": attrs.string(default = "apk"),
|
||||
},
|
||||
"gen_aidl": {
|
||||
"import_paths": attrs.list(attrs.arg(), default = []),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
},
|
||||
"prebuilt_native_library": {
|
||||
"native_libs": attrs.source(allow_directory = True),
|
||||
},
|
||||
"robolectric_test": {
|
||||
"resources_root": attrs.option(attrs.string(), default = None),
|
||||
"robolectric_runtime_dependencies": attrs.list(attrs.source(), default = []),
|
||||
"_android_toolchain": android_toolchain(),
|
||||
"_is_building_android_binary": attrs.default_only(attrs.bool(default = False)),
|
||||
"_java_test_toolchain": attrs.default_only(attrs.exec_dep(
|
||||
default = select_java_test_toolchain(),
|
||||
providers = [
|
||||
JavaTestToolchainInfo,
|
||||
],
|
||||
)),
|
||||
"_java_toolchain": java_toolchain_for_android(),
|
||||
"_kotlin_toolchain": _kotlin_toolchain(),
|
||||
},
|
||||
}
|
||||
334
vendor/cxx/tools/buck/prelude/android/android_apk.bzl
vendored
Normal file
334
vendor/cxx/tools/buck/prelude/android/android_apk.bzl
vendored
Normal file
|
|
@ -0,0 +1,334 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_binary_native_library_rules.bzl", "get_android_binary_native_library_info")
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_build_config.bzl", "generate_android_build_config", "get_build_config_fields")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo", "BuildConfigField", "CPU_FILTER_TO_ABI_DIRECTORY", "ExopackageInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:configuration.bzl", "get_deps_by_platform")
|
||||
load("@prelude//android:dex_rules.bzl", "get_multi_dex", "get_single_primary_dex", "get_split_dex_merge_config", "merge_to_single_dex", "merge_to_split_dex")
|
||||
load("@prelude//android:exopackage.bzl", "get_exopackage_flags")
|
||||
load("@prelude//android:preprocess_java_classes.bzl", "get_preprocessed_java_classes")
|
||||
load("@prelude//android:proguard.bzl", "get_proguard_output")
|
||||
load("@prelude//android:voltron.bzl", "get_target_to_module_mapping")
|
||||
load("@prelude//java:java_providers.bzl", "KeystoreInfo", "create_java_packaging_dep", "get_all_java_packaging_deps", "get_all_java_packaging_deps_from_packaging_infos")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def android_apk_impl(ctx: "context") -> ["provider"]:
|
||||
sub_targets = {}
|
||||
|
||||
_verify_params(ctx)
|
||||
|
||||
cpu_filters = ctx.attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
deps_by_platform = get_deps_by_platform(ctx)
|
||||
primary_platform = cpu_filters[0]
|
||||
deps = deps_by_platform[primary_platform]
|
||||
|
||||
no_dx_target_labels = [no_dx_target.label.raw_target() for no_dx_target in ctx.attrs.no_dx]
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, deps) if packaging_dep.dex and packaging_dep.dex.dex.owner.raw_target() not in no_dx_target_labels]
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, deps)
|
||||
build_config_infos = list(android_packageable_info.build_config_infos.traverse()) if android_packageable_info.build_config_infos else []
|
||||
|
||||
build_config_libs = _get_build_config_java_libraries(ctx, build_config_infos)
|
||||
java_packaging_deps += get_all_java_packaging_deps_from_packaging_infos(ctx, build_config_libs)
|
||||
|
||||
has_proguard_config = ctx.attrs.proguard_config != None or ctx.attrs.android_sdk_proguard_config == "default" or ctx.attrs.android_sdk_proguard_config == "optimized"
|
||||
should_pre_dex = not ctx.attrs.disable_pre_dex and not has_proguard_config and not ctx.attrs.preprocess_java_classes_bash
|
||||
|
||||
referenced_resources_lists = [java_packaging_dep.dex.referenced_resources for java_packaging_dep in java_packaging_deps] if ctx.attrs.trim_resource_ids and should_pre_dex else []
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps,
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = referenced_resources_lists,
|
||||
manifest_entries = ctx.attrs.manifest_entries,
|
||||
)
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
java_packaging_deps += [
|
||||
create_java_packaging_dep(
|
||||
ctx,
|
||||
r_dot_java.library_output.full_library,
|
||||
dex_weight_factor = android_toolchain.r_dot_java_weight_factor,
|
||||
)
|
||||
for r_dot_java in resources_info.r_dot_javas
|
||||
]
|
||||
|
||||
target_to_module_mapping_file = get_target_to_module_mapping(ctx, deps)
|
||||
if should_pre_dex:
|
||||
pre_dexed_libs = [java_packaging_dep.dex for java_packaging_dep in java_packaging_deps]
|
||||
if ctx.attrs.use_split_dex:
|
||||
dex_files_info = merge_to_split_dex(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
pre_dexed_libs,
|
||||
get_split_dex_merge_config(ctx, android_toolchain),
|
||||
target_to_module_mapping_file,
|
||||
)
|
||||
else:
|
||||
dex_files_info = merge_to_single_dex(ctx, android_toolchain, pre_dexed_libs)
|
||||
else:
|
||||
jars_to_owners = {packaging_dep.jar: packaging_dep.jar.owner.raw_target() for packaging_dep in java_packaging_deps}
|
||||
if ctx.attrs.preprocess_java_classes_bash:
|
||||
jars_to_owners = get_preprocessed_java_classes(ctx, jars_to_owners)
|
||||
if has_proguard_config:
|
||||
proguard_output = get_proguard_output(ctx, jars_to_owners, java_packaging_deps, resources_info.proguard_config_file)
|
||||
jars_to_owners = proguard_output.jars_to_owners
|
||||
sub_targets["proguard_text_output"] = [
|
||||
DefaultInfo(
|
||||
default_outputs = [ctx.actions.symlinked_dir(
|
||||
"proguard_text_output",
|
||||
{artifact.basename: artifact for artifact in proguard_output.proguard_artifacts},
|
||||
)],
|
||||
),
|
||||
]
|
||||
else:
|
||||
proguard_output = None
|
||||
|
||||
if ctx.attrs.use_split_dex:
|
||||
dex_files_info = get_multi_dex(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
jars_to_owners,
|
||||
ctx.attrs.primary_dex_patterns,
|
||||
proguard_output.proguard_configuration_output_file if proguard_output else None,
|
||||
proguard_output.proguard_mapping_output_file if proguard_output else None,
|
||||
is_optimized = has_proguard_config,
|
||||
apk_module_graph_file = target_to_module_mapping_file,
|
||||
)
|
||||
else:
|
||||
dex_files_info = get_single_primary_dex(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
jars_to_owners.keys(),
|
||||
is_optimized = has_proguard_config,
|
||||
)
|
||||
|
||||
native_library_info = get_android_binary_native_library_info(ctx, android_packageable_info, deps_by_platform, apk_module_graph_file = target_to_module_mapping_file)
|
||||
unstripped_native_libs = native_library_info.unstripped_libs
|
||||
sub_targets["unstripped_native_libraries"] = [
|
||||
DefaultInfo(
|
||||
default_outputs = [ctx.actions.write("unstripped_native_libraries", unstripped_native_libs)],
|
||||
other_outputs = unstripped_native_libs,
|
||||
),
|
||||
]
|
||||
if resources_info.string_source_map:
|
||||
sub_targets["generate_string_resources"] = [DefaultInfo(default_outputs = [resources_info.string_source_map])]
|
||||
|
||||
if dex_files_info.primary_dex_class_names:
|
||||
sub_targets["primary_dex_class_names"] = [DefaultInfo(default_outputs = [dex_files_info.primary_dex_class_names])]
|
||||
|
||||
keystore = ctx.attrs.keystore[KeystoreInfo]
|
||||
output_apk = build_apk(
|
||||
label = ctx.label,
|
||||
actions = ctx.actions,
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
keystore = keystore,
|
||||
dex_files_info = dex_files_info,
|
||||
native_library_info = native_library_info,
|
||||
resources_info = resources_info,
|
||||
compress_resources_dot_arsc = ctx.attrs.resource_compression == "enabled" or ctx.attrs.resource_compression == "enabled_with_strings_as_assets",
|
||||
)
|
||||
|
||||
exopackage_info = ExopackageInfo(
|
||||
secondary_dex_info = dex_files_info.secondary_dex_exopackage_info,
|
||||
native_library_info = native_library_info.exopackage_info,
|
||||
resources_info = resources_info.exopackage_info,
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidApkInfo(apk = output_apk, manifest = resources_info.manifest),
|
||||
AndroidApkUnderTestInfo(
|
||||
java_packaging_deps = java_packaging_deps,
|
||||
keystore = keystore,
|
||||
manifest_entries = ctx.attrs.manifest_entries,
|
||||
prebuilt_native_library_dirs = native_library_info.apk_under_test_prebuilt_native_library_dirs,
|
||||
platforms = deps_by_platform.keys(),
|
||||
primary_platform = primary_platform,
|
||||
resource_infos = resources_info.unfiltered_resource_infos,
|
||||
shared_libraries = native_library_info.apk_under_test_shared_libraries,
|
||||
),
|
||||
DefaultInfo(default_outputs = [output_apk], other_outputs = _get_exopackage_outputs(exopackage_info), sub_targets = sub_targets),
|
||||
_get_install_info(ctx, output_apk = output_apk, manifest = resources_info.manifest, exopackage_info = exopackage_info),
|
||||
]
|
||||
|
||||
def build_apk(
|
||||
label: "label",
|
||||
actions: "actions",
|
||||
keystore: KeystoreInfo.type,
|
||||
android_toolchain: AndroidToolchainInfo.type,
|
||||
dex_files_info: "DexFilesInfo",
|
||||
native_library_info: "AndroidBinaryNativeLibsInfo",
|
||||
resources_info: "AndroidBinaryResourcesInfo",
|
||||
compress_resources_dot_arsc: bool.type = False) -> "artifact":
|
||||
output_apk = actions.declare_output("{}.apk".format(label.name))
|
||||
|
||||
apk_builder_args = cmd_args([
|
||||
android_toolchain.apk_builder[RunInfo],
|
||||
"--output-apk",
|
||||
output_apk.as_output(),
|
||||
"--resource-apk",
|
||||
resources_info.primary_resources_apk,
|
||||
"--dex-file",
|
||||
dex_files_info.primary_dex,
|
||||
"--keystore-path",
|
||||
keystore.store,
|
||||
"--keystore-properties-path",
|
||||
keystore.properties,
|
||||
"--zipalign_tool",
|
||||
android_toolchain.zipalign[RunInfo],
|
||||
])
|
||||
|
||||
if compress_resources_dot_arsc:
|
||||
apk_builder_args.add("--compress-resources-dot-arsc")
|
||||
|
||||
asset_directories = native_library_info.native_lib_assets + dex_files_info.secondary_dex_dirs
|
||||
asset_directories_file = actions.write("asset_directories.txt", asset_directories)
|
||||
apk_builder_args.hidden(asset_directories)
|
||||
native_library_directories = actions.write("native_library_directories", native_library_info.native_libs_for_primary_apk)
|
||||
apk_builder_args.hidden(native_library_info.native_libs_for_primary_apk)
|
||||
all_zip_files = [resources_info.packaged_string_assets] if resources_info.packaged_string_assets else []
|
||||
zip_files = actions.write("zip_files", all_zip_files)
|
||||
apk_builder_args.hidden(all_zip_files)
|
||||
jar_files_that_may_contain_resources = actions.write("jar_files_that_may_contain_resources", resources_info.jar_files_that_may_contain_resources)
|
||||
apk_builder_args.hidden(resources_info.jar_files_that_may_contain_resources)
|
||||
|
||||
apk_builder_args.add([
|
||||
"--asset-directories-list",
|
||||
asset_directories_file,
|
||||
"--native-libraries-directories-list",
|
||||
native_library_directories,
|
||||
"--zip-files-list",
|
||||
zip_files,
|
||||
"--jar-files-that-may-contain-resources-list",
|
||||
jar_files_that_may_contain_resources,
|
||||
])
|
||||
|
||||
actions.run(apk_builder_args, category = "apk_build")
|
||||
|
||||
return output_apk
|
||||
|
||||
def _get_install_info(ctx: "context", output_apk: "artifact", manifest: "artifact", exopackage_info: ExopackageInfo.type) -> InstallInfo.type:
|
||||
files = {
|
||||
ctx.attrs.name: output_apk,
|
||||
"manifest": manifest,
|
||||
"options": generate_install_config(ctx),
|
||||
}
|
||||
|
||||
secondary_dex_exopackage_info = exopackage_info.secondary_dex_info
|
||||
if secondary_dex_exopackage_info:
|
||||
files["secondary_dex_exopackage_info_directory"] = secondary_dex_exopackage_info.directory
|
||||
files["secondary_dex_exopackage_info_metadata"] = secondary_dex_exopackage_info.metadata
|
||||
|
||||
native_library_exopackage_info = exopackage_info.native_library_info
|
||||
if native_library_exopackage_info:
|
||||
files["native_library_exopackage_info_directory"] = native_library_exopackage_info.directory
|
||||
files["native_library_exopackage_info_metadata"] = native_library_exopackage_info.metadata
|
||||
|
||||
resources_info = exopackage_info.resources_info
|
||||
if resources_info:
|
||||
if resources_info.assets:
|
||||
files["resources_exopackage_assets"] = resources_info.assets
|
||||
files["resources_exopackage_assets_hash"] = resources_info.assets_hash
|
||||
|
||||
files["resources_exopackage_res"] = resources_info.res
|
||||
files["resources_exopackage_res_hash"] = resources_info.res_hash
|
||||
files["resources_exopackage_third_party_jar_resources"] = resources_info.third_party_jar_resources
|
||||
files["resources_exopackage_third_party_jar_resources_hash"] = resources_info.third_party_jar_resources_hash
|
||||
|
||||
if secondary_dex_exopackage_info or native_library_exopackage_info or resources_info:
|
||||
files["exopackage_agent_apk"] = ctx.attrs._android_toolchain[AndroidToolchainInfo].exopackage_agent_apk
|
||||
|
||||
return InstallInfo(
|
||||
installer = ctx.attrs._android_installer,
|
||||
files = files,
|
||||
)
|
||||
|
||||
def _get_build_config_java_libraries(ctx: "context", build_config_infos: ["AndroidBuildConfigInfo"]) -> ["JavaPackagingInfo"]:
|
||||
# BuildConfig deps should not be added for instrumented APKs because BuildConfig.class has
|
||||
# already been added to the APK under test.
|
||||
if ctx.attrs.package_type == "instrumented":
|
||||
return []
|
||||
|
||||
build_config_constants = [
|
||||
BuildConfigField(type = "boolean", name = "DEBUG", value = str(ctx.attrs.package_type != "release").lower()),
|
||||
BuildConfigField(type = "boolean", name = "IS_EXOPACKAGE", value = str(len(ctx.attrs.exopackage_modes) > 0).lower()),
|
||||
BuildConfigField(type = "int", name = "EXOPACKAGE_FLAGS", value = str(get_exopackage_flags(ctx.attrs.exopackage_modes))),
|
||||
]
|
||||
|
||||
default_build_config_fields = get_build_config_fields(ctx.attrs.build_config_values)
|
||||
|
||||
java_libraries = []
|
||||
java_packages_seen = []
|
||||
for build_config_info in build_config_infos:
|
||||
java_package = build_config_info.package
|
||||
expect(java_package not in java_packages_seen, "Got the same java_package {} for different AndroidBuildConfigs".format(java_package))
|
||||
java_packages_seen.append(java_package)
|
||||
|
||||
all_build_config_values = {}
|
||||
for build_config_field in build_config_info.build_config_fields + default_build_config_fields + build_config_constants:
|
||||
all_build_config_values[build_config_field.name] = build_config_field
|
||||
|
||||
java_libraries.append(generate_android_build_config(
|
||||
ctx,
|
||||
java_package,
|
||||
java_package,
|
||||
True, # use_constant_expressions
|
||||
all_build_config_values.values(),
|
||||
ctx.attrs.build_config_values_file[DefaultInfo].default_outputs[0] if type(ctx.attrs.build_config_values_file) == "dependency" else ctx.attrs.build_config_values_file,
|
||||
)[1])
|
||||
|
||||
return java_libraries
|
||||
|
||||
def _get_exopackage_outputs(exopackage_info: ExopackageInfo.type) -> ["artifact"]:
|
||||
outputs = []
|
||||
secondary_dex_exopackage_info = exopackage_info.secondary_dex_info
|
||||
if secondary_dex_exopackage_info:
|
||||
outputs.append(secondary_dex_exopackage_info.metadata)
|
||||
outputs.append(secondary_dex_exopackage_info.directory)
|
||||
|
||||
native_library_exopackage_info = exopackage_info.native_library_info
|
||||
if native_library_exopackage_info:
|
||||
outputs.append(native_library_exopackage_info.metadata)
|
||||
outputs.append(native_library_exopackage_info.directory)
|
||||
|
||||
resources_info = exopackage_info.resources_info
|
||||
if resources_info:
|
||||
outputs.append(resources_info.res)
|
||||
outputs.append(resources_info.res_hash)
|
||||
outputs.append(resources_info.third_party_jar_resources)
|
||||
outputs.append(resources_info.third_party_jar_resources_hash)
|
||||
|
||||
if resources_info.assets:
|
||||
outputs.append(resources_info.assets)
|
||||
outputs.append(resources_info.assets_hash)
|
||||
|
||||
return outputs
|
||||
|
||||
def _verify_params(ctx: "context"):
|
||||
expect(ctx.attrs.aapt_mode == "aapt2", "aapt1 is deprecated!")
|
||||
expect(ctx.attrs.dex_tool == "d8", "dx is deprecated!")
|
||||
expect(ctx.attrs.allow_r_dot_java_in_secondary_dex == True)
|
||||
|
||||
def generate_install_config(ctx: "context") -> "artifact":
|
||||
data = get_install_config()
|
||||
return ctx.actions.write_json("install_android_options.json", data)
|
||||
|
||||
def get_install_config() -> {str.type: ""}:
|
||||
# TODO: read from toolchains
|
||||
return {
|
||||
"adb_executable": read_config("android", "adb", "/opt/android_sdk/platform-tools/adb"),
|
||||
"adb_restart_on_failure": read_config("adb", "adb_restart_on_failure", "false"),
|
||||
"agent_port_base": read_config("adb", "agent_port_base", "2828"),
|
||||
"always_use_java_agent": read_config("adb", "always_use_java_agent", "false"),
|
||||
"is_zstd_compression_enabled": read_config("adb", "is_zstd_compression_enabled", "false"),
|
||||
"multi_install_mode": read_config("adb", "multi_install_mode", "false"),
|
||||
"skip_install_metadata": read_config("adb", "skip_install_metadata", "false"),
|
||||
}
|
||||
404
vendor/cxx/tools/buck/prelude/android/android_binary_native_library_rules.bzl
vendored
Normal file
404
vendor/cxx/tools/buck/prelude/android/android_binary_native_library_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,404 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:paths.bzl", "paths")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidBinaryNativeLibsInfo", "CPU_FILTER_TO_ABI_DIRECTORY", "ExopackageNativeInfo")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:voltron.bzl", "ROOT_MODULE", "all_targets_in_root_module", "get_apk_module_graph_info", "is_root_module")
|
||||
load("@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", "traverse_shared_library_info")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
# Native libraries on Android are built for a particular Application Binary Interface (ABI). We
|
||||
# package native libraries for one (or more, for multi-arch builds) ABIs into an Android APK.
|
||||
#
|
||||
# Our native libraries come from two sources:
|
||||
# 1. "Prebuilt native library dirs", which are directory artifacts whose sub-directories are ABIs,
|
||||
# and those ABI subdirectories contain native libraries. These come from `android_prebuilt_aar`s
|
||||
# and `prebuilt_native_library`s, for example.
|
||||
# 2. "Native linkables". These are each a single shared library - `.so`s for one particular ABI.
|
||||
#
|
||||
# Native libraries can be packaged into Android APKs in two ways.
|
||||
# 1. As native libraries. This means that they are passed to the APK builder as native libraries,
|
||||
# and the APK builder will package `<ABI>/library.so` into the APK at `libs/<ABI>/library.so`.
|
||||
# 2. As assets. These are passed to the APK build as assets, and are stored at
|
||||
# `assets/lib/<ABI>/library.so` In the root module, we only package a native library as an
|
||||
# asset if it is eligible to be an asset (e.g. `can_be_asset` on a `cxx_library`), and
|
||||
# `package_asset_libraries` is set to True for the APK. We will additionally compress all the
|
||||
# assets into a single `assets/lib/libs.xz` (or `assets/libs/libs.zstd` for `zstd` compression)
|
||||
# if `compress_asset_libraries` is set to True for the APK. Regardless of whether we compress
|
||||
# the assets or not, we create a metadata file at `assets/libs/metadata.txt` that has a single
|
||||
# line entry for each packaged asset consisting of '<ABI/library_name> <file_size> <sha256>'.
|
||||
#
|
||||
# Any native library that is not part of the root module (i.e. it is part of some other Voltron
|
||||
# module) is automatically packaged as an asset, and the assets for each module are compressed
|
||||
# to a single `assets/<module_name>/libs.xz`. Similarly, the metadata for each module is stored
|
||||
# at `assets/<module_name>/libs.txt`.
|
||||
|
||||
def get_android_binary_native_library_info(
|
||||
ctx: "context",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
deps_by_platform: {str.type: ["dependency"]},
|
||||
apk_module_graph_file: ["artifact", None] = None,
|
||||
prebuilt_native_library_dirs_to_exclude: ["PrebuiltNativeLibraryDir"] = [],
|
||||
shared_libraries_to_exclude: ["SharedLibrary"] = []) -> AndroidBinaryNativeLibsInfo.type:
|
||||
traversed_prebuilt_native_library_dirs = android_packageable_info.prebuilt_native_library_dirs.traverse() if android_packageable_info.prebuilt_native_library_dirs else []
|
||||
all_prebuilt_native_library_dirs = [native_lib for native_lib in traversed_prebuilt_native_library_dirs if native_lib not in prebuilt_native_library_dirs_to_exclude]
|
||||
|
||||
unstripped_libs = []
|
||||
all_shared_libraries = []
|
||||
platform_to_native_linkables = {}
|
||||
for platform, deps in deps_by_platform.items():
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in deps]),
|
||||
)
|
||||
native_linkables = {so_name: shared_lib for so_name, shared_lib in traverse_shared_library_info(shared_library_info).items() if shared_lib not in shared_libraries_to_exclude}
|
||||
all_shared_libraries.extend(native_linkables.values())
|
||||
unstripped_libs += [shared_lib.lib.output for shared_lib in native_linkables.values()]
|
||||
platform_to_native_linkables[platform] = native_linkables
|
||||
|
||||
if apk_module_graph_file == None:
|
||||
native_libs_and_assets_info = _get_native_libs_and_assets(
|
||||
ctx,
|
||||
all_targets_in_root_module,
|
||||
all_prebuilt_native_library_dirs,
|
||||
platform_to_native_linkables,
|
||||
)
|
||||
native_libs_for_primary_apk, exopackage_info = _get_exopackage_info(
|
||||
ctx,
|
||||
native_libs_and_assets_info.native_libs_always_in_primary_apk,
|
||||
native_libs_and_assets_info.native_libs,
|
||||
native_libs_and_assets_info.native_libs_metadata,
|
||||
)
|
||||
native_lib_assets = filter(None, [
|
||||
native_libs_and_assets_info.native_lib_assets_for_primary_apk,
|
||||
native_libs_and_assets_info.stripped_native_linkable_assets_for_primary_apk,
|
||||
native_libs_and_assets_info.metadata_assets,
|
||||
native_libs_and_assets_info.compressed_lib_assets,
|
||||
])
|
||||
return AndroidBinaryNativeLibsInfo(
|
||||
apk_under_test_prebuilt_native_library_dirs = all_prebuilt_native_library_dirs,
|
||||
apk_under_test_shared_libraries = all_shared_libraries,
|
||||
native_libs_for_primary_apk = native_libs_for_primary_apk,
|
||||
exopackage_info = exopackage_info,
|
||||
unstripped_libs = unstripped_libs,
|
||||
native_lib_assets = native_lib_assets,
|
||||
)
|
||||
else:
|
||||
native_libs = ctx.actions.declare_output("native_libs_symlink")
|
||||
native_libs_metadata = ctx.actions.declare_output("native_libs_metadata_symlink")
|
||||
native_libs_always_in_primary_apk = ctx.actions.declare_output("native_libs_always_in_primary_apk_symlink")
|
||||
native_lib_assets_for_primary_apk = ctx.actions.declare_output("native_lib_assets_for_primary_apk_symlink")
|
||||
stripped_native_linkable_assets_for_primary_apk = ctx.actions.declare_output("stripped_native_linkable_assets_for_primary_apk_symlink")
|
||||
metadata_assets = ctx.actions.declare_output("metadata_assets_symlink")
|
||||
compressed_lib_assets = ctx.actions.declare_output("compressed_lib_assets_symlink")
|
||||
|
||||
outputs = [
|
||||
native_libs,
|
||||
native_libs_metadata,
|
||||
native_libs_always_in_primary_apk,
|
||||
native_lib_assets_for_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
metadata_assets,
|
||||
compressed_lib_assets,
|
||||
]
|
||||
|
||||
def get_native_libs_info_modular(ctx: "context", artifacts, outputs):
|
||||
get_module_from_target = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts).target_to_module_mapping_function
|
||||
dynamic_info = _get_native_libs_and_assets(
|
||||
ctx,
|
||||
get_module_from_target,
|
||||
all_prebuilt_native_library_dirs,
|
||||
platform_to_native_linkables,
|
||||
)
|
||||
|
||||
# Since we are using a dynamic action, we need to declare the outputs in advance.
|
||||
# Rather than passing the created outputs into `_get_native_libs_and_assets`, we
|
||||
# just symlink to the outputs that function produces.
|
||||
ctx.actions.symlink_file(outputs[native_libs], dynamic_info.native_libs)
|
||||
ctx.actions.symlink_file(outputs[native_libs_metadata], dynamic_info.native_libs_metadata)
|
||||
ctx.actions.symlink_file(outputs[native_libs_always_in_primary_apk], dynamic_info.native_libs_always_in_primary_apk)
|
||||
ctx.actions.symlink_file(outputs[native_lib_assets_for_primary_apk], dynamic_info.native_lib_assets_for_primary_apk if dynamic_info.native_lib_assets_for_primary_apk else ctx.actions.symlinked_dir("empty_native_lib_assets", {}))
|
||||
ctx.actions.symlink_file(outputs[stripped_native_linkable_assets_for_primary_apk], dynamic_info.stripped_native_linkable_assets_for_primary_apk if dynamic_info.stripped_native_linkable_assets_for_primary_apk else ctx.actions.symlinked_dir("empty_stripped_native_linkable_assets", {}))
|
||||
ctx.actions.symlink_file(outputs[metadata_assets], dynamic_info.metadata_assets)
|
||||
ctx.actions.symlink_file(outputs[compressed_lib_assets], dynamic_info.compressed_lib_assets)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = [apk_module_graph_file], inputs = [], outputs = outputs, f = get_native_libs_info_modular)
|
||||
|
||||
native_libs_for_primary_apk, exopackage_info = _get_exopackage_info(ctx, native_libs_always_in_primary_apk, native_libs, native_libs_metadata)
|
||||
return AndroidBinaryNativeLibsInfo(
|
||||
apk_under_test_prebuilt_native_library_dirs = all_prebuilt_native_library_dirs,
|
||||
apk_under_test_shared_libraries = all_shared_libraries,
|
||||
native_libs_for_primary_apk = native_libs_for_primary_apk,
|
||||
exopackage_info = exopackage_info,
|
||||
unstripped_libs = unstripped_libs,
|
||||
native_lib_assets = [native_lib_assets_for_primary_apk, stripped_native_linkable_assets_for_primary_apk, metadata_assets, compressed_lib_assets],
|
||||
)
|
||||
|
||||
# We could just return two artifacts of libs (one for the primary APK, one which can go
|
||||
# either into the primary APK or be exopackaged), and one artifact of assets,
|
||||
# but we'd need an extra action in order to combine them (we can't use `symlinked_dir` since
|
||||
# the paths overlap) so it's easier to just be explicit about exactly what we produce.
|
||||
_NativeLibsAndAssetsInfo = record(
|
||||
native_libs = "artifact",
|
||||
native_libs_metadata = "artifact",
|
||||
native_libs_always_in_primary_apk = "artifact",
|
||||
native_lib_assets_for_primary_apk = ["artifact", None],
|
||||
stripped_native_linkable_assets_for_primary_apk = ["artifact", None],
|
||||
metadata_assets = "artifact",
|
||||
compressed_lib_assets = "artifact",
|
||||
)
|
||||
|
||||
def _get_exopackage_info(
|
||||
ctx: "context",
|
||||
native_libs_always_in_primary_apk: "artifact",
|
||||
native_libs: "artifact",
|
||||
native_libs_metadata: "artifact") -> (["artifact"], [ExopackageNativeInfo.type, None]):
|
||||
is_exopackage_enabled_for_native_libs = "native_library" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
if is_exopackage_enabled_for_native_libs:
|
||||
return [native_libs_always_in_primary_apk], ExopackageNativeInfo(directory = native_libs, metadata = native_libs_metadata)
|
||||
else:
|
||||
return [native_libs, native_libs_always_in_primary_apk], None
|
||||
|
||||
def _get_native_libs_and_assets(
|
||||
ctx: "context",
|
||||
get_module_from_target: "function",
|
||||
all_prebuilt_native_library_dirs: ["PrebuiltNativeLibraryDir"],
|
||||
platform_to_native_linkables: {str.type: {str.type: "SharedLibrary"}}) -> _NativeLibsAndAssetsInfo.type:
|
||||
is_packaging_native_libs_as_assets_supported = getattr(ctx.attrs, "package_asset_libraries", False)
|
||||
|
||||
prebuilt_native_library_dirs = []
|
||||
prebuilt_native_library_dirs_always_in_primary_apk = []
|
||||
prebuilt_native_library_dir_assets_for_primary_apk = []
|
||||
prebuilt_native_library_dir_module_assets_map = {}
|
||||
for native_lib in all_prebuilt_native_library_dirs:
|
||||
native_lib_target = str(native_lib.raw_target)
|
||||
module = get_module_from_target(native_lib_target)
|
||||
if not is_root_module(module):
|
||||
# In buck1, we always package native libs as assets when they are not in the root module
|
||||
expect(not native_lib.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be included in non-root-module {}".format(native_lib_target, module))
|
||||
prebuilt_native_library_dir_module_assets_map.setdefault(module, []).append(native_lib)
|
||||
elif native_lib.is_asset and is_packaging_native_libs_as_assets_supported:
|
||||
expect(not native_lib.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be an asset".format(native_lib_target))
|
||||
prebuilt_native_library_dir_assets_for_primary_apk.append(native_lib)
|
||||
elif native_lib.for_primary_apk:
|
||||
prebuilt_native_library_dirs_always_in_primary_apk.append(native_lib)
|
||||
else:
|
||||
prebuilt_native_library_dirs.append(native_lib)
|
||||
|
||||
native_libs = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dirs,
|
||||
"native_libs",
|
||||
)
|
||||
native_libs_always_in_primary_apk = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dirs_always_in_primary_apk,
|
||||
"native_libs_always_in_primary_apk",
|
||||
)
|
||||
native_lib_assets_for_primary_apk = _filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
prebuilt_native_library_dir_assets_for_primary_apk,
|
||||
"native_lib_assets_for_primary_apk",
|
||||
package_as_assets = True,
|
||||
module = ROOT_MODULE,
|
||||
) if prebuilt_native_library_dir_assets_for_primary_apk else None
|
||||
native_lib_module_assets_map = {}
|
||||
for module, native_lib_dir in prebuilt_native_library_dir_module_assets_map.items():
|
||||
native_lib_module_assets_map[module] = [_filter_prebuilt_native_library_dir(
|
||||
ctx,
|
||||
native_lib_dir,
|
||||
"native_lib_assets_for_module_{}".format(module),
|
||||
package_as_assets = True,
|
||||
module = module,
|
||||
)]
|
||||
|
||||
(
|
||||
stripped_native_linkables,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
stripped_native_linkable_module_assets_map,
|
||||
) = _get_native_linkables(ctx, platform_to_native_linkables, get_module_from_target, is_packaging_native_libs_as_assets_supported)
|
||||
for module, native_linkable_assets in stripped_native_linkable_module_assets_map.items():
|
||||
native_lib_module_assets_map.setdefault(module, []).append(native_linkable_assets)
|
||||
|
||||
metadata_srcs = {}
|
||||
compressed_lib_srcs = {}
|
||||
assets_for_primary_apk = filter(None, [native_lib_assets_for_primary_apk, stripped_native_linkable_assets_for_primary_apk])
|
||||
if assets_for_primary_apk:
|
||||
metadata_file, native_library_paths = _get_native_libs_as_assets_metadata(ctx, assets_for_primary_apk, ROOT_MODULE)
|
||||
metadata_srcs[paths.join(_get_native_libs_as_assets_dir(ROOT_MODULE), "metadata.txt")] = metadata_file
|
||||
if ctx.attrs.compress_asset_libraries:
|
||||
compressed_lib_dir = _get_compressed_native_libs_as_assets(ctx, assets_for_primary_apk, native_library_paths, ROOT_MODULE)
|
||||
compressed_lib_srcs[_get_native_libs_as_assets_dir(ROOT_MODULE)] = compressed_lib_dir
|
||||
|
||||
# Since we're storing these as compressed assets, we need to ignore the uncompressed libs.
|
||||
native_lib_assets_for_primary_apk = None
|
||||
stripped_native_linkable_assets_for_primary_apk = None
|
||||
|
||||
for module, native_lib_assets in native_lib_module_assets_map.items():
|
||||
metadata_file, native_library_paths = _get_native_libs_as_assets_metadata(ctx, native_lib_assets, module)
|
||||
metadata_srcs[paths.join(_get_native_libs_as_assets_dir(module), "libs.txt")] = metadata_file
|
||||
compressed_lib_dir = _get_compressed_native_libs_as_assets(ctx, native_lib_assets, native_library_paths, module)
|
||||
compressed_lib_srcs[_get_native_libs_as_assets_dir(module)] = compressed_lib_dir
|
||||
|
||||
combined_native_libs = ctx.actions.declare_output("combined_native_libs")
|
||||
native_libs_metadata = ctx.actions.declare_output("native_libs_metadata.txt")
|
||||
ctx.actions.run(cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].combine_native_library_dirs[RunInfo],
|
||||
"--output-dir",
|
||||
combined_native_libs.as_output(),
|
||||
"--library-dirs",
|
||||
native_libs,
|
||||
stripped_native_linkables,
|
||||
"--metadata-file",
|
||||
native_libs_metadata.as_output(),
|
||||
]), category = "combine_native_libs")
|
||||
|
||||
combined_native_libs_always_in_primary_apk = ctx.actions.declare_output("combined_native_libs_always_in_primary_apk")
|
||||
ctx.actions.run(cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].combine_native_library_dirs[RunInfo],
|
||||
"--output-dir",
|
||||
combined_native_libs_always_in_primary_apk.as_output(),
|
||||
"--library-dirs",
|
||||
native_libs_always_in_primary_apk,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
]), category = "combine_native_libs_always_in_primary_apk")
|
||||
|
||||
return _NativeLibsAndAssetsInfo(
|
||||
native_libs = combined_native_libs,
|
||||
native_libs_metadata = native_libs_metadata,
|
||||
native_libs_always_in_primary_apk = combined_native_libs_always_in_primary_apk,
|
||||
native_lib_assets_for_primary_apk = native_lib_assets_for_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk = stripped_native_linkable_assets_for_primary_apk,
|
||||
metadata_assets = ctx.actions.symlinked_dir("metadata_assets", metadata_srcs),
|
||||
compressed_lib_assets = ctx.actions.symlinked_dir("compressed_lib_assets", compressed_lib_srcs),
|
||||
)
|
||||
|
||||
def _filter_prebuilt_native_library_dir(
|
||||
ctx: "context",
|
||||
native_libs: ["PrebuiltNativeLibraryDir"],
|
||||
identifier: str.type,
|
||||
package_as_assets: bool.type = False,
|
||||
module: str.type = ROOT_MODULE) -> "artifact":
|
||||
cpu_filters = ctx.attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
abis = [CPU_FILTER_TO_ABI_DIRECTORY[cpu] for cpu in cpu_filters]
|
||||
filter_tool = ctx.attrs._android_toolchain[AndroidToolchainInfo].filter_prebuilt_native_library_dir[RunInfo]
|
||||
native_libs_dirs = [native_lib.dir for native_lib in native_libs]
|
||||
native_libs_dirs_file = ctx.actions.write("{}_list.txt".format(identifier), native_libs_dirs)
|
||||
base_output_dir = ctx.actions.declare_output(identifier)
|
||||
output_dir = base_output_dir.project(_get_native_libs_as_assets_dir(module)) if package_as_assets else base_output_dir
|
||||
ctx.actions.run(
|
||||
cmd_args([filter_tool, native_libs_dirs_file, output_dir.as_output(), "--abis"] + abis).hidden(native_libs_dirs),
|
||||
category = "filter_prebuilt_native_library_dir",
|
||||
identifier = identifier,
|
||||
)
|
||||
|
||||
return base_output_dir
|
||||
|
||||
def _get_native_linkables(
|
||||
ctx: "context",
|
||||
platform_to_native_linkables: {str.type: {str.type: "SharedLibrary"}},
|
||||
get_module_from_target: "function",
|
||||
package_native_libs_as_assets_enabled: bool.type) -> ("artifact", "artifact", ["artifact", None], {str.type: "artifact"}):
|
||||
stripped_native_linkables_srcs = {}
|
||||
stripped_native_linkables_always_in_primary_apk_srcs = {}
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs = {}
|
||||
stripped_native_linkable_module_assets_srcs = {}
|
||||
|
||||
cpu_filters = ctx.attrs.cpu_filters
|
||||
for platform, native_linkables in platform_to_native_linkables.items():
|
||||
if cpu_filters and platform not in cpu_filters:
|
||||
fail("Platform `{}` is not in the CPU filters `{}`".format(platform, cpu_filters))
|
||||
|
||||
abi_directory = CPU_FILTER_TO_ABI_DIRECTORY[platform]
|
||||
for so_name, native_linkable in native_linkables.items():
|
||||
native_linkable_target = str(native_linkable.label.raw_target())
|
||||
module = get_module_from_target(native_linkable_target)
|
||||
|
||||
if not is_root_module(module):
|
||||
expect(not native_linkable.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be included in non-root-module {}".format(native_linkable_target, module))
|
||||
so_name_path = paths.join(_get_native_libs_as_assets_dir(module), abi_directory, so_name)
|
||||
stripped_native_linkable_module_assets_srcs.setdefault(module, {})[so_name_path] = native_linkable.stripped_lib
|
||||
elif native_linkable.can_be_asset and package_native_libs_as_assets_enabled:
|
||||
expect(not native_linkable.for_primary_apk, "{} which is marked as needing to be in the primary APK cannot be an asset".format(native_linkable_target))
|
||||
so_name_path = paths.join(_get_native_libs_as_assets_dir(module), abi_directory, so_name)
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
else:
|
||||
so_name_path = paths.join(abi_directory, so_name)
|
||||
if native_linkable.for_primary_apk:
|
||||
stripped_native_linkables_always_in_primary_apk_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
else:
|
||||
stripped_native_linkables_srcs[so_name_path] = native_linkable.stripped_lib
|
||||
|
||||
stripped_native_linkables = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables",
|
||||
stripped_native_linkables_srcs,
|
||||
)
|
||||
stripped_native_linkables_always_in_primary_apk = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables_always_in_primary_apk",
|
||||
stripped_native_linkables_always_in_primary_apk_srcs,
|
||||
)
|
||||
stripped_native_linkable_assets_for_primary_apk = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkables_assets_for_primary_apk",
|
||||
stripped_native_linkable_assets_for_primary_apk_srcs,
|
||||
) if stripped_native_linkable_assets_for_primary_apk_srcs else None
|
||||
stripped_native_linkable_module_assets_map = {}
|
||||
for module, srcs in stripped_native_linkable_module_assets_srcs.items():
|
||||
stripped_native_linkable_module_assets_map[module] = ctx.actions.symlinked_dir(
|
||||
"stripped_native_linkable_assets_for_module_{}".format(module),
|
||||
srcs,
|
||||
)
|
||||
|
||||
return (
|
||||
stripped_native_linkables,
|
||||
stripped_native_linkables_always_in_primary_apk,
|
||||
stripped_native_linkable_assets_for_primary_apk,
|
||||
stripped_native_linkable_module_assets_map,
|
||||
)
|
||||
|
||||
def _get_native_libs_as_assets_metadata(
|
||||
ctx: "context",
|
||||
native_lib_assets: ["artifact"],
|
||||
module: str.type) -> ("artifact", "artifact"):
|
||||
native_lib_assets_file = ctx.actions.write("{}/native_lib_assets".format(module), [cmd_args([native_lib_asset, _get_native_libs_as_assets_dir(module)], delimiter = "/") for native_lib_asset in native_lib_assets])
|
||||
metadata_output = ctx.actions.declare_output("{}/native_libs_as_assets_metadata.txt".format(module))
|
||||
native_library_paths = ctx.actions.declare_output("{}/native_libs_as_assets_paths.txt".format(module))
|
||||
metadata_cmd = cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].native_libs_as_assets_metadata[RunInfo],
|
||||
"--native-library-dirs",
|
||||
native_lib_assets_file,
|
||||
"--metadata-output",
|
||||
metadata_output.as_output(),
|
||||
"--native-library-paths-output",
|
||||
native_library_paths.as_output(),
|
||||
]).hidden(native_lib_assets)
|
||||
ctx.actions.run(metadata_cmd, category = "get_native_libs_as_assets_metadata", identifier = module)
|
||||
return metadata_output, native_library_paths
|
||||
|
||||
def _get_compressed_native_libs_as_assets(
|
||||
ctx: "context",
|
||||
native_lib_assets: ["artifact"],
|
||||
native_library_paths: "artifact",
|
||||
module: str.type) -> "artifact":
|
||||
output_dir = ctx.actions.declare_output("{}/compressed_native_libs_as_assets_dir".format(module))
|
||||
compressed_libraries_cmd = cmd_args([
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].compress_libraries[RunInfo],
|
||||
"--libraries",
|
||||
native_library_paths,
|
||||
"--output-dir",
|
||||
output_dir.as_output(),
|
||||
"--compression-type",
|
||||
ctx.attrs.asset_compression_algorithm or "xz",
|
||||
"--xz-compression-level",
|
||||
str(ctx.attrs.xz_compression_level),
|
||||
]).hidden(native_lib_assets)
|
||||
ctx.actions.run(compressed_libraries_cmd, category = "compress_native_libs_as_assets", identifier = module)
|
||||
return output_dir
|
||||
|
||||
def _get_native_libs_as_assets_dir(module: str.type) -> str.type:
|
||||
return "assets/{}".format("lib" if is_root_module(module) else module)
|
||||
473
vendor/cxx/tools/buck/prelude/android/android_binary_resources_rules.bzl
vendored
Normal file
473
vendor/cxx/tools/buck/prelude/android/android_binary_resources_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,473 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:attributes.bzl", "RType")
|
||||
load("@prelude//:resources.bzl", "gather_resources")
|
||||
load("@prelude//android:aapt2_link.bzl", "get_aapt2_link")
|
||||
load("@prelude//android:android_manifest.bzl", "generate_android_manifest")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidBinaryResourcesInfo", "AndroidResourceInfo", "ExopackageResourcesInfo")
|
||||
load("@prelude//android:android_resource.bzl", "aapt2_compile")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:r_dot_java.bzl", "generate_r_dot_javas")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def get_android_binary_resources_info(
|
||||
ctx: "context",
|
||||
deps: ["dependency"],
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
java_packaging_deps: ["JavaPackagingDep"],
|
||||
use_proto_format: bool.type,
|
||||
referenced_resources_lists: ["artifact"],
|
||||
manifest_entries: dict.type = {},
|
||||
resource_infos_to_exclude: [AndroidResourceInfo.type] = []) -> "AndroidBinaryResourcesInfo":
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
unfiltered_resource_infos = [resource_info for resource_info in list(android_packageable_info.resource_infos.traverse() if android_packageable_info.resource_infos else []) if resource_info not in resource_infos_to_exclude]
|
||||
resource_infos, override_symbols, string_files_list, string_files_res_dirs = _maybe_filter_resources(
|
||||
ctx,
|
||||
unfiltered_resource_infos,
|
||||
android_toolchain,
|
||||
)
|
||||
|
||||
android_manifest = _get_manifest(ctx, android_packageable_info, manifest_entries)
|
||||
|
||||
aapt2_link_info = get_aapt2_link(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
[resource_info.aapt2_compile_output for resource_info in resource_infos if resource_info.aapt2_compile_output != None],
|
||||
android_manifest,
|
||||
includes_vector_drawables = getattr(ctx.attrs, "includes_vector_drawables", False),
|
||||
no_auto_version = getattr(ctx.attrs, "no_auto_version_resources", False),
|
||||
no_version_transitions = getattr(ctx.attrs, "no_version_transitions_resources", False),
|
||||
no_auto_add_overlay = getattr(ctx.attrs, "no_auto_add_overlay_resources", False),
|
||||
use_proto_format = use_proto_format,
|
||||
no_resource_removal = True,
|
||||
package_id_offset = 0,
|
||||
should_keep_raw_values = getattr(ctx.attrs, "aapt2_keep_raw_values", False),
|
||||
resource_stable_ids = getattr(ctx.attrs, "resource_stable_ids", None),
|
||||
compiled_resource_apks = [],
|
||||
additional_aapt2_params = getattr(ctx.attrs, "additional_aapt_params", []),
|
||||
extra_filtered_resources = getattr(ctx.attrs, "extra_filtered_resources", []),
|
||||
locales = getattr(ctx.attrs, "locales", []),
|
||||
filter_locales = getattr(ctx.attrs, "aapt2_locale_filtering", False),
|
||||
)
|
||||
|
||||
prebuilt_jars = [packaging_dep.jar for packaging_dep in java_packaging_deps if packaging_dep.is_prebuilt_jar]
|
||||
|
||||
cxx_resources = _get_cxx_resources(ctx, deps)
|
||||
is_exopackaged_enabled_for_resources = "resources" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
primary_resources_apk, exopackaged_assets, exopackaged_assets_hash = _merge_assets(
|
||||
ctx,
|
||||
is_exopackaged_enabled_for_resources,
|
||||
aapt2_link_info.primary_resources_apk,
|
||||
resource_infos,
|
||||
cxx_resources,
|
||||
)
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
r_dot_txt = ctx.actions.declare_output("after_exo/R.txt")
|
||||
primary_resources_apk = ctx.actions.declare_output("after_exo/primary_resources_apk.apk")
|
||||
exo_resources = ctx.actions.declare_output("exo_resources.apk")
|
||||
exo_resources_hash = ctx.actions.declare_output("exo_resources.apk.hash")
|
||||
ctx.actions.run(cmd_args([
|
||||
android_toolchain.exo_resources_rewriter[RunInfo],
|
||||
"--original-r-dot-txt",
|
||||
aapt2_link_info.r_dot_txt,
|
||||
"--new-r-dot-txt",
|
||||
r_dot_txt.as_output(),
|
||||
"--original-primary-apk-resources",
|
||||
aapt2_link_info.primary_resources_apk,
|
||||
"--new-primary-apk-resources",
|
||||
primary_resources_apk.as_output(),
|
||||
"--exo-resources",
|
||||
exo_resources.as_output(),
|
||||
"--exo-resources-hash",
|
||||
exo_resources_hash.as_output(),
|
||||
"--zipalign-tool",
|
||||
android_toolchain.zipalign[RunInfo],
|
||||
]), category = "write_exo_resources")
|
||||
|
||||
third_party_jars = ctx.actions.write("third_party_jars", prebuilt_jars)
|
||||
third_party_jar_resources = ctx.actions.declare_output("third_party_jars.resources")
|
||||
third_party_jar_resources_hash = ctx.actions.declare_output("third_party_jars.resources.hash")
|
||||
ctx.actions.run(cmd_args([
|
||||
android_toolchain.merge_third_party_jar_resources[RunInfo],
|
||||
"--output",
|
||||
third_party_jar_resources.as_output(),
|
||||
"--output-hash",
|
||||
third_party_jar_resources_hash.as_output(),
|
||||
"--third-party-jars",
|
||||
third_party_jars,
|
||||
]).hidden(prebuilt_jars), category = "merge_third_party_jar_resources")
|
||||
|
||||
exopackage_info = ExopackageResourcesInfo(
|
||||
assets = exopackaged_assets,
|
||||
assets_hash = exopackaged_assets_hash,
|
||||
res = exo_resources,
|
||||
res_hash = exo_resources_hash,
|
||||
third_party_jar_resources = third_party_jar_resources,
|
||||
third_party_jar_resources_hash = third_party_jar_resources_hash,
|
||||
)
|
||||
jar_files_that_may_contain_resources = []
|
||||
else:
|
||||
exopackage_info = None
|
||||
jar_files_that_may_contain_resources = prebuilt_jars
|
||||
r_dot_txt = aapt2_link_info.r_dot_txt
|
||||
|
||||
override_symbols_paths = [override_symbols] if override_symbols else []
|
||||
resources = [resource for resource in resource_infos if resource.res != None]
|
||||
r_dot_javas = [] if len(resources) == 0 else generate_r_dot_javas(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_android_resources[RunInfo],
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo],
|
||||
resources,
|
||||
get_effective_banned_duplicate_resource_types(
|
||||
getattr(ctx.attrs, "duplicate_resource_behavior", "allow_by_default"),
|
||||
getattr(ctx.attrs, "allowed_duplicate_resource_types", []),
|
||||
getattr(ctx.attrs, "banned_duplicate_resource_types", []),
|
||||
),
|
||||
[r_dot_txt],
|
||||
override_symbols_paths,
|
||||
getattr(ctx.attrs, "duplicate_resource_whitelist", None),
|
||||
getattr(ctx.attrs, "resource_union_package", None),
|
||||
referenced_resources_lists,
|
||||
)
|
||||
string_source_map = _maybe_generate_string_source_map(
|
||||
ctx.actions,
|
||||
getattr(ctx.attrs, "build_string_source_map", False),
|
||||
resources,
|
||||
android_toolchain,
|
||||
)
|
||||
packaged_string_assets = _maybe_package_strings_as_assets(
|
||||
ctx,
|
||||
string_files_list,
|
||||
string_files_res_dirs,
|
||||
r_dot_txt,
|
||||
android_toolchain,
|
||||
)
|
||||
|
||||
return AndroidBinaryResourcesInfo(
|
||||
exopackage_info = exopackage_info,
|
||||
manifest = android_manifest,
|
||||
packaged_string_assets = packaged_string_assets,
|
||||
primary_resources_apk = primary_resources_apk,
|
||||
proguard_config_file = aapt2_link_info.proguard_config_file,
|
||||
r_dot_javas = r_dot_javas,
|
||||
string_source_map = string_source_map,
|
||||
jar_files_that_may_contain_resources = jar_files_that_may_contain_resources,
|
||||
unfiltered_resource_infos = unfiltered_resource_infos,
|
||||
)
|
||||
|
||||
def _maybe_filter_resources(
|
||||
ctx: "context",
|
||||
resources: [AndroidResourceInfo.type],
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ([AndroidResourceInfo.type], ["artifact", None], ["artifact", None], ["artifact"]):
|
||||
resources_filter_strings = getattr(ctx.attrs, "resource_filter", [])
|
||||
resources_filter = _get_resources_filter(resources_filter_strings)
|
||||
resource_compression_mode = getattr(ctx.attrs, "resource_compression", "disabled")
|
||||
is_store_strings_as_assets = _is_store_strings_as_assets(resource_compression_mode)
|
||||
locales = getattr(ctx.attrs, "locales", None)
|
||||
use_aapt2_locale_filtering = getattr(ctx.attrs, "aapt2_locale_filtering", False)
|
||||
needs_resource_filtering_for_locales = locales != None and len(locales) > 0 and not use_aapt2_locale_filtering
|
||||
post_filter_resources_cmd = getattr(ctx.attrs, "post_filter_resources_cmd", None)
|
||||
|
||||
needs_resource_filtering = (
|
||||
resources_filter != None or
|
||||
is_store_strings_as_assets or
|
||||
needs_resource_filtering_for_locales or
|
||||
post_filter_resources_cmd != None
|
||||
)
|
||||
|
||||
if not needs_resource_filtering:
|
||||
return resources, None, None, []
|
||||
|
||||
res_info_to_out_res_dir = {}
|
||||
res_infos_with_no_res = []
|
||||
skip_crunch_pngs = getattr(ctx.attrs, "skip_crunch_pngs", None) or False
|
||||
for i, resource in enumerate(resources):
|
||||
if resource.res == None:
|
||||
res_infos_with_no_res.append(resource)
|
||||
else:
|
||||
filtered_res = ctx.actions.declare_output("filtered_res_{}".format(i))
|
||||
res_info_to_out_res_dir[resource] = filtered_res
|
||||
|
||||
filter_resources_cmd = cmd_args(android_toolchain.filter_resources[RunInfo])
|
||||
in_res_dir_to_out_res_dir_dict = {
|
||||
in_res.res: out_res
|
||||
for in_res, out_res in res_info_to_out_res_dir.items()
|
||||
}
|
||||
in_res_dir_to_out_res_dir_map = ctx.actions.write_json("in_res_dir_to_out_res_dir_map", {"res_dir_map": in_res_dir_to_out_res_dir_dict})
|
||||
in_res_dirs = [in_res.res for in_res in res_info_to_out_res_dir.keys()]
|
||||
filter_resources_cmd.hidden(in_res_dirs)
|
||||
filter_resources_cmd.hidden([out_res.as_output() for out_res in res_info_to_out_res_dir.values()])
|
||||
filter_resources_cmd.add([
|
||||
"--in-res-dir-to-out-res-dir-map",
|
||||
in_res_dir_to_out_res_dir_map,
|
||||
])
|
||||
|
||||
if resources_filter:
|
||||
filter_resources_cmd.add([
|
||||
"--target-densities",
|
||||
",".join(resources_filter.densities),
|
||||
])
|
||||
|
||||
all_strings_files_list = None
|
||||
all_strings_files_res_dirs = []
|
||||
if is_store_strings_as_assets:
|
||||
all_strings_files_list = ctx.actions.declare_output("all_strings_files")
|
||||
all_strings_files_res_dirs = in_res_dirs
|
||||
filter_resources_cmd.add([
|
||||
"--enable-string-as-assets-filtering",
|
||||
"--string-files-list-output",
|
||||
all_strings_files_list.as_output(),
|
||||
])
|
||||
|
||||
packaged_locales = getattr(ctx.attrs, "packaged_locales", [])
|
||||
if packaged_locales:
|
||||
filter_resources_cmd.add([
|
||||
"--packaged-locales",
|
||||
",".join(packaged_locales),
|
||||
])
|
||||
|
||||
not_filtered_string_dirs = [resource.res for resource in resources if not resource.allow_strings_as_assets_resource_filtering]
|
||||
if not_filtered_string_dirs:
|
||||
filter_resources_cmd.add([
|
||||
"--not-filtered-string-dirs",
|
||||
ctx.actions.write("not_filtered_string_dirs", not_filtered_string_dirs),
|
||||
])
|
||||
|
||||
if needs_resource_filtering_for_locales:
|
||||
filter_resources_cmd.add([
|
||||
"--locales",
|
||||
",".join(locales),
|
||||
])
|
||||
|
||||
override_symbols_artifact = None
|
||||
if post_filter_resources_cmd != None:
|
||||
override_symbols_artifact = ctx.actions.declare_output("post_filter_resources_cmd/R.json")
|
||||
filter_resources_cmd.add([
|
||||
"--post-filter-resources-cmd",
|
||||
post_filter_resources_cmd,
|
||||
"--post-filter-resources-cmd-override-symbols-output",
|
||||
override_symbols_artifact.as_output(),
|
||||
])
|
||||
|
||||
ctx.actions.run(filter_resources_cmd, category = "filter_resources")
|
||||
|
||||
filtered_resource_infos = []
|
||||
for i, resource in enumerate(resources):
|
||||
if resource.res == None:
|
||||
continue
|
||||
|
||||
filtered_res = res_info_to_out_res_dir[resource]
|
||||
filtered_aapt2_compile_output = aapt2_compile(
|
||||
ctx,
|
||||
filtered_res,
|
||||
android_toolchain,
|
||||
skip_crunch_pngs = skip_crunch_pngs,
|
||||
identifier = "filtered_res_{}".format(i),
|
||||
)
|
||||
filtered_resource = AndroidResourceInfo(
|
||||
aapt2_compile_output = filtered_aapt2_compile_output,
|
||||
assets = resource.assets,
|
||||
manifest_file = resource.manifest_file,
|
||||
r_dot_java_package = resource.r_dot_java_package,
|
||||
res = filtered_res,
|
||||
text_symbols = resource.text_symbols,
|
||||
)
|
||||
filtered_resource_infos.append(filtered_resource)
|
||||
|
||||
return (
|
||||
res_infos_with_no_res + filtered_resource_infos,
|
||||
override_symbols_artifact,
|
||||
all_strings_files_list,
|
||||
all_strings_files_res_dirs,
|
||||
)
|
||||
|
||||
ResourcesFilter = record(
|
||||
densities = [str.type],
|
||||
downscale = bool.type,
|
||||
)
|
||||
|
||||
def _get_resources_filter(resources_filter_strings: [str.type]) -> [ResourcesFilter.type, None]:
|
||||
if not resources_filter_strings:
|
||||
return None
|
||||
|
||||
densities = [resources_filter_string for resources_filter_string in resources_filter_strings if resources_filter_string != "downscale"]
|
||||
if not densities:
|
||||
return None
|
||||
|
||||
downscale = len(densities) < len(resources_filter_strings)
|
||||
return ResourcesFilter(densities = densities, downscale = downscale)
|
||||
|
||||
def _maybe_generate_string_source_map(
|
||||
actions: "actions",
|
||||
should_build_source_string_map: bool.type,
|
||||
resource_infos: [AndroidResourceInfo.type],
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ["artifact", None]:
|
||||
if not should_build_source_string_map or len(resource_infos) == 0:
|
||||
return None
|
||||
|
||||
res_dirs = [resource_info.res for resource_info in resource_infos]
|
||||
output = actions.declare_output("string_source_map")
|
||||
res_dirs_file = actions.write("resource_dirs_for_string_source_map", res_dirs)
|
||||
generate_string_source_map_cmd = cmd_args([
|
||||
android_toolchain.copy_string_resources[RunInfo],
|
||||
"--res-dirs",
|
||||
res_dirs_file,
|
||||
"--output",
|
||||
output.as_output(),
|
||||
]).hidden(res_dirs)
|
||||
|
||||
actions.run(generate_string_source_map_cmd, category = "generate_string_source_map")
|
||||
|
||||
return output
|
||||
|
||||
def _maybe_package_strings_as_assets(
|
||||
ctx: "context",
|
||||
string_files_list: ["artifact", None],
|
||||
string_files_res_dirs: ["artifact"],
|
||||
r_dot_txt: "artifact",
|
||||
android_toolchain: AndroidToolchainInfo.type) -> ["artifact", None]:
|
||||
resource_compression_mode = getattr(ctx.attrs, "resource_compression", "disabled")
|
||||
is_store_strings_as_assets = _is_store_strings_as_assets(resource_compression_mode)
|
||||
expect(is_store_strings_as_assets == (string_files_list != None))
|
||||
|
||||
if not is_store_strings_as_assets:
|
||||
return None
|
||||
|
||||
string_assets_dir = ctx.actions.declare_output("package_strings_as_assets/string_assets")
|
||||
string_assets_zip = ctx.actions.declare_output("package_strings_as_assets/string_assets_zip.zip")
|
||||
all_locales_string_assets_zip = ctx.actions.declare_output("package_strings_as_assets/all_locales_string_assets_zip.zip")
|
||||
|
||||
locales = getattr(ctx.attrs, "locales", [])
|
||||
|
||||
package_strings_as_assets_cmd = cmd_args([
|
||||
android_toolchain.package_strings_as_assets[RunInfo],
|
||||
"--string-files-list",
|
||||
string_files_list,
|
||||
"--r-dot-txt",
|
||||
r_dot_txt,
|
||||
"--string-assets-dir",
|
||||
string_assets_dir.as_output(),
|
||||
"--string-assets-zip",
|
||||
string_assets_zip.as_output(),
|
||||
"--all-locales-string-assets-zip",
|
||||
all_locales_string_assets_zip.as_output(),
|
||||
]).hidden(string_files_res_dirs)
|
||||
|
||||
if locales:
|
||||
package_strings_as_assets_cmd.add("--locales", ",".join(locales))
|
||||
|
||||
ctx.actions.run(package_strings_as_assets_cmd, category = "package_strings_as_assets")
|
||||
|
||||
return string_assets_zip
|
||||
|
||||
def _get_manifest(
|
||||
ctx: "context",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
manifest_entries: dict.type) -> "artifact":
|
||||
robolectric_manifest = getattr(ctx.attrs, "robolectric_manifest", None)
|
||||
if robolectric_manifest:
|
||||
return robolectric_manifest
|
||||
|
||||
if ctx.attrs.manifest:
|
||||
expect(ctx.attrs.manifest_skeleton == None, "Only one of manifest and manifest_skeleton should be declared")
|
||||
if type(ctx.attrs.manifest) == "dependency":
|
||||
android_manifest = ctx.attrs.manifest[DefaultInfo].default_outputs[0]
|
||||
else:
|
||||
android_manifest = ctx.attrs.manifest
|
||||
else:
|
||||
expect(ctx.attrs.manifest_skeleton != None, "Must declare one of manifest and manifest_skeleton")
|
||||
if type(ctx.attrs.manifest_skeleton) == "dependency":
|
||||
manifest_skeleton = ctx.attrs.manifest_skeleton[DefaultInfo].default_outputs[0]
|
||||
else:
|
||||
manifest_skeleton = ctx.attrs.manifest_skeleton
|
||||
android_manifest, _ = generate_android_manifest(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_manifest[RunInfo],
|
||||
manifest_skeleton,
|
||||
"dex", # ROOT_APKMODULE_NAME,
|
||||
android_packageable_info.manifests,
|
||||
manifest_entries.get("placeholders", {}),
|
||||
)
|
||||
|
||||
return android_manifest
|
||||
|
||||
# Returns the "primary resources APK" (i.e. the resource that are packaged into the primary APK),
|
||||
# and optionally an "exopackaged assets APK" and the hash for that APK.
|
||||
def _merge_assets(
|
||||
ctx: "context",
|
||||
is_exopackaged_enabled_for_resources: bool.type,
|
||||
base_apk: "artifact",
|
||||
resource_infos: ["AndroidResourceInfo"],
|
||||
cxx_resources: ["artifact", None]) -> ("artifact", ["artifact", None], ["artifact", None]):
|
||||
assets_dirs = [resource_info.assets for resource_info in resource_infos if resource_info.assets]
|
||||
if cxx_resources != None:
|
||||
assets_dirs.extend([cxx_resources])
|
||||
if len(assets_dirs) == 0:
|
||||
return base_apk, None, None
|
||||
|
||||
merge_assets_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_assets[RunInfo])
|
||||
|
||||
merged_assets_output = ctx.actions.declare_output("merged_assets.ap_")
|
||||
merge_assets_cmd.add(["--output-apk", merged_assets_output.as_output()])
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
merged_assets_output_hash = ctx.actions.declare_output("merged_assets.ap_.hash")
|
||||
merge_assets_cmd.add(["--output-apk-hash", merged_assets_output_hash.as_output()])
|
||||
else:
|
||||
merge_assets_cmd.add(["--base-apk", base_apk])
|
||||
merged_assets_output_hash = None
|
||||
|
||||
assets_dirs_file = ctx.actions.write("assets_dirs", assets_dirs)
|
||||
merge_assets_cmd.add(["--assets-dirs", assets_dirs_file])
|
||||
merge_assets_cmd.hidden(assets_dirs)
|
||||
|
||||
ctx.actions.run(merge_assets_cmd, category = "merge_assets")
|
||||
|
||||
if is_exopackaged_enabled_for_resources:
|
||||
return base_apk, merged_assets_output, merged_assets_output_hash
|
||||
else:
|
||||
return merged_assets_output, None, None
|
||||
|
||||
def get_effective_banned_duplicate_resource_types(
|
||||
duplicate_resource_behavior: str.type,
|
||||
allowed_duplicate_resource_types: [str.type],
|
||||
banned_duplicate_resource_types: [str.type]) -> [str.type]:
|
||||
if duplicate_resource_behavior == "allow_by_default":
|
||||
expect(
|
||||
len(allowed_duplicate_resource_types) == 0,
|
||||
"Cannot set allowed_duplicate_resource_types if duplicate_resource_behaviour is allow_by_default",
|
||||
)
|
||||
return banned_duplicate_resource_types
|
||||
elif duplicate_resource_behavior == "ban_by_default":
|
||||
expect(
|
||||
len(banned_duplicate_resource_types) == 0,
|
||||
"Cannot set banned_duplicate_resource_types if duplicate_resource_behaviour is ban_by_default",
|
||||
)
|
||||
return [rtype for rtype in RType if rtype not in allowed_duplicate_resource_types]
|
||||
else:
|
||||
fail("Unrecognized duplicate_resource_behavior: {}".format(duplicate_resource_behavior))
|
||||
|
||||
def _get_cxx_resources(ctx: "context", deps: ["dependency"]) -> ["artifact", None]:
|
||||
cxx_resources = gather_resources(
|
||||
label = ctx.label,
|
||||
resources = {},
|
||||
deps = deps,
|
||||
)
|
||||
|
||||
symlink_tree_dict = {}
|
||||
resource_maps = cxx_resources.values()
|
||||
for resource_map in resource_maps:
|
||||
for name, (resource, _other) in resource_map.items():
|
||||
symlink_tree_dict["cxx-resources/{}".format(name)] = resource
|
||||
|
||||
return ctx.actions.symlinked_dir("cxx_resources_dir", symlink_tree_dict) if symlink_tree_dict else None
|
||||
|
||||
def _is_store_strings_as_assets(resource_compression: str.type) -> bool.type:
|
||||
return resource_compression == "enabled_strings_only" or resource_compression == "enabled_with_strings_as_assets"
|
||||
113
vendor/cxx/tools/buck/prelude/android/android_build_config.bzl
vendored
Normal file
113
vendor/cxx/tools/buck/prelude/android/android_build_config.bzl
vendored
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//java:java_providers.bzl", "JavaLibraryInfo", "JavaPackagingDepTSet", "JavaPackagingInfo", "create_java_packaging_dep", "derive_compiling_deps")
|
||||
load(":android_providers.bzl", "AndroidBuildConfigInfo", "BuildConfigField", "merge_android_packageable_info")
|
||||
|
||||
def android_build_config_impl(ctx: "context") -> ["provider"]:
|
||||
providers = []
|
||||
|
||||
default_build_config_fields = get_build_config_fields(ctx.attrs.values)
|
||||
android_build_config_info = AndroidBuildConfigInfo(package = ctx.attrs.package, build_config_fields = default_build_config_fields)
|
||||
providers.append(android_build_config_info)
|
||||
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, deps = [], build_config_info = android_build_config_info))
|
||||
|
||||
build_config_dot_java_library, java_packaging_info = generate_android_build_config(
|
||||
ctx,
|
||||
ctx.attrs.name,
|
||||
ctx.attrs.package,
|
||||
False,
|
||||
default_build_config_fields,
|
||||
ctx.attrs.values_file,
|
||||
)
|
||||
|
||||
providers.append(java_packaging_info)
|
||||
providers.append(build_config_dot_java_library)
|
||||
|
||||
providers.append(DefaultInfo(default_outputs = [build_config_dot_java_library.library_output.full_library]))
|
||||
return providers
|
||||
|
||||
def generate_android_build_config(
|
||||
ctx: "context",
|
||||
source: str.type,
|
||||
java_package: str.type,
|
||||
use_constant_expressions: bool.type,
|
||||
default_values: ["BuildConfigField"],
|
||||
values_file: ["artifact", None]) -> ("JavaLibraryInfo", "JavaPackagingInfo"):
|
||||
build_config_dot_java = _generate_build_config_dot_java(ctx, source, java_package, use_constant_expressions, default_values, values_file)
|
||||
|
||||
compiled_build_config_dot_java = _compile_and_package_build_config_dot_java(ctx, java_package, build_config_dot_java)
|
||||
library_output = compiled_build_config_dot_java.classpath_entry
|
||||
|
||||
packaging_deps_kwargs = {"value": create_java_packaging_dep(ctx, library_output.full_library)}
|
||||
packaging_deps = ctx.actions.tset(JavaPackagingDepTSet, **packaging_deps_kwargs)
|
||||
return (JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
), JavaPackagingInfo(
|
||||
packaging_deps = packaging_deps,
|
||||
))
|
||||
|
||||
def _generate_build_config_dot_java(
|
||||
ctx: "context",
|
||||
source: str.type,
|
||||
java_package: str.type,
|
||||
use_constant_expressions: bool.type,
|
||||
default_values: ["BuildConfigField"],
|
||||
values_file: ["artifact", None]) -> "artifact":
|
||||
generate_build_config_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_build_config[RunInfo])
|
||||
generate_build_config_cmd.add([
|
||||
"--source",
|
||||
source,
|
||||
"--java-package",
|
||||
java_package,
|
||||
"--use-constant-expressions",
|
||||
str(use_constant_expressions),
|
||||
])
|
||||
|
||||
default_values_file = ctx.actions.write(
|
||||
_get_output_name(java_package, "default_values"),
|
||||
["{} {} = {}".format(x.type, x.name, x.value) for x in default_values],
|
||||
)
|
||||
generate_build_config_cmd.add(["--default-values-file", default_values_file])
|
||||
if values_file:
|
||||
generate_build_config_cmd.add(["--values-file", values_file])
|
||||
|
||||
build_config_dot_java = ctx.actions.declare_output(_get_output_name(java_package, "BuildConfig.java"))
|
||||
generate_build_config_cmd.add(["--output", build_config_dot_java.as_output()])
|
||||
|
||||
ctx.actions.run(
|
||||
generate_build_config_cmd,
|
||||
category = "android_generate_build_config",
|
||||
identifier = java_package,
|
||||
)
|
||||
|
||||
return build_config_dot_java
|
||||
|
||||
def _compile_and_package_build_config_dot_java(
|
||||
ctx: "context",
|
||||
java_package: str.type,
|
||||
build_config_dot_java: "artifact") -> "JavaCompileOutputs":
|
||||
return compile_to_jar(
|
||||
ctx,
|
||||
actions_prefix = "build_config_{}".format(java_package.replace(".", "_")),
|
||||
srcs = [build_config_dot_java],
|
||||
)
|
||||
|
||||
def get_build_config_fields(lines: [str.type]) -> ["BuildConfigField"]:
|
||||
return [_get_build_config_field(line) for line in lines]
|
||||
|
||||
def _get_build_config_field(line: str.type) -> "BuildConfigField":
|
||||
type_and_name, value = [x.strip() for x in line.split("=")]
|
||||
field_type, name = type_and_name.split()
|
||||
return BuildConfigField(type = field_type, name = name, value = value)
|
||||
|
||||
def _get_output_name(java_package: str.type, output_filename: str.type) -> str.type:
|
||||
return "android_build_config/{}/{}".format(java_package.replace(".", "_"), output_filename)
|
||||
89
vendor/cxx/tools/buck/prelude/android/android_instrumentation_apk.bzl
vendored
Normal file
89
vendor/cxx/tools/buck/prelude/android/android_instrumentation_apk.bzl
vendored
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_apk.bzl", "build_apk")
|
||||
load("@prelude//android:android_binary_native_library_rules.bzl", "get_android_binary_native_library_info")
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo", "AndroidInstrumentationApkInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:configuration.bzl", "get_deps_by_platform")
|
||||
load("@prelude//android:dex_rules.bzl", "merge_to_single_dex")
|
||||
load("@prelude//java:java_providers.bzl", "create_java_packaging_dep", "get_all_java_packaging_deps")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def android_instrumentation_apk_impl(ctx: "context"):
|
||||
# To begin with, let's just implement something that has a single DEX file and a manifest.
|
||||
_verify_params(ctx)
|
||||
|
||||
apk_under_test_info = ctx.attrs.apk[AndroidApkUnderTestInfo]
|
||||
|
||||
# android_instrumentation_apk should just use the same platforms and primary_platform as the APK-under-test
|
||||
unfiltered_deps_by_platform = get_deps_by_platform(ctx)
|
||||
for platform in apk_under_test_info.platforms:
|
||||
expect(
|
||||
platform in unfiltered_deps_by_platform,
|
||||
"Android instrumentation APK must have any platforms that are in the APK-under-test!",
|
||||
)
|
||||
deps_by_platform = {platform: deps for platform, deps in unfiltered_deps_by_platform.items() if platform in apk_under_test_info.platforms}
|
||||
primary_platform = apk_under_test_info.primary_platform
|
||||
deps = deps_by_platform[primary_platform]
|
||||
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, deps) if packaging_dep.dex and packaging_dep not in apk_under_test_info.java_packaging_deps]
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, deps)
|
||||
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps = java_packaging_deps,
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = [],
|
||||
manifest_entries = apk_under_test_info.manifest_entries,
|
||||
resource_infos_to_exclude = apk_under_test_info.resource_infos,
|
||||
)
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
java_packaging_deps += [
|
||||
create_java_packaging_dep(
|
||||
ctx,
|
||||
r_dot_java.library_output.full_library,
|
||||
dex_weight_factor = android_toolchain.r_dot_java_weight_factor,
|
||||
)
|
||||
for r_dot_java in resources_info.r_dot_javas
|
||||
]
|
||||
|
||||
# For instrumentation test APKs we always pre-dex, and we also always merge to a single dex.
|
||||
pre_dexed_libs = [java_packaging_dep.dex for java_packaging_dep in java_packaging_deps]
|
||||
dex_files_info = merge_to_single_dex(ctx, android_toolchain, pre_dexed_libs)
|
||||
|
||||
native_library_info = get_android_binary_native_library_info(
|
||||
ctx,
|
||||
android_packageable_info,
|
||||
deps_by_platform,
|
||||
prebuilt_native_library_dirs_to_exclude = apk_under_test_info.prebuilt_native_library_dirs,
|
||||
shared_libraries_to_exclude = apk_under_test_info.shared_libraries,
|
||||
)
|
||||
|
||||
output_apk = build_apk(
|
||||
label = ctx.label,
|
||||
actions = ctx.actions,
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
keystore = apk_under_test_info.keystore,
|
||||
dex_files_info = dex_files_info,
|
||||
native_library_info = native_library_info,
|
||||
resources_info = resources_info,
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidApkInfo(apk = output_apk, manifest = resources_info.manifest),
|
||||
AndroidInstrumentationApkInfo(apk_under_test = ctx.attrs.apk[AndroidApkInfo].apk),
|
||||
DefaultInfo(default_outputs = [output_apk]),
|
||||
]
|
||||
|
||||
def _verify_params(ctx: "context"):
|
||||
expect(ctx.attrs.aapt_mode == "aapt2", "aapt1 is deprecated!")
|
||||
expect(ctx.attrs.dex_tool == "d8", "dx is deprecated!")
|
||||
97
vendor/cxx/tools/buck/prelude/android/android_instrumentation_test.bzl
vendored
Normal file
97
vendor/cxx/tools/buck/prelude/android/android_instrumentation_test.bzl
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidInstrumentationApkInfo")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load("@prelude//test/inject_test_run_info.bzl", "inject_test_run_info")
|
||||
|
||||
def android_instrumentation_test_impl(ctx: "context"):
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
|
||||
cmd = [ctx.attrs._java_toolchain[JavaToolchainInfo].java_for_tests]
|
||||
|
||||
classpath = android_toolchain.instrumentation_test_runner_classpath
|
||||
|
||||
classpath_args = cmd_args()
|
||||
classpath_args.add("-classpath")
|
||||
classpath_args.add(cmd_args(classpath, delimiter = get_path_separator()))
|
||||
classpath_args_file = ctx.actions.write("classpath_args_file", classpath_args)
|
||||
cmd.append(cmd_args(classpath_args_file, format = "@{}").hidden(classpath_args))
|
||||
|
||||
cmd.append(android_toolchain.instrumentation_test_runner_main_class)
|
||||
|
||||
apk_info = ctx.attrs.apk.get(AndroidApkInfo)
|
||||
expect(apk_info != None, "Provided APK must have AndroidApkInfo!")
|
||||
|
||||
instrumentation_apk_info = ctx.attrs.apk.get(AndroidInstrumentationApkInfo)
|
||||
if instrumentation_apk_info != None:
|
||||
cmd.extend(["--apk-under-test-path", instrumentation_apk_info.apk_under_test])
|
||||
|
||||
target_package_file = ctx.actions.declare_output("target_package_file")
|
||||
package_file = ctx.actions.declare_output("package_file")
|
||||
test_runner_file = ctx.actions.declare_output("test_runner_file")
|
||||
manifest_utils_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].manifest_utils[RunInfo])
|
||||
manifest_utils_cmd.add([
|
||||
"--manifest-path",
|
||||
apk_info.manifest,
|
||||
"--package-output",
|
||||
package_file.as_output(),
|
||||
"--target-package-output",
|
||||
target_package_file.as_output(),
|
||||
"--instrumentation-test-runner-output",
|
||||
test_runner_file.as_output(),
|
||||
])
|
||||
ctx.actions.run(manifest_utils_cmd, category = "get_manifest_info")
|
||||
|
||||
cmd.extend(
|
||||
[
|
||||
"--test-package-name",
|
||||
cmd_args(package_file, format = "@{}"),
|
||||
"--target-package-name",
|
||||
cmd_args(target_package_file, format = "@{}"),
|
||||
"--test-runner",
|
||||
cmd_args(test_runner_file, format = "@{}"),
|
||||
],
|
||||
)
|
||||
|
||||
cmd.extend(
|
||||
[
|
||||
"--adb-executable-path",
|
||||
"required_but_unused",
|
||||
"--instrumentation-apk-path",
|
||||
apk_info.apk,
|
||||
],
|
||||
)
|
||||
|
||||
test_info = ExternalRunnerTestInfo(
|
||||
type = "android_instrumentation",
|
||||
command = cmd,
|
||||
env = ctx.attrs.env,
|
||||
# TODO(T122022107) support static listing
|
||||
labels = ctx.attrs.labels + ["tpx::dynamic_listing_instrumentation_test"],
|
||||
contacts = ctx.attrs.contacts,
|
||||
run_from_project_root = True,
|
||||
use_project_relative_paths = True,
|
||||
executor_overrides = {
|
||||
"android-emulator": CommandExecutorConfig(
|
||||
local_enabled = False,
|
||||
remote_enabled = True,
|
||||
remote_execution_properties = {
|
||||
"platform": "android-emulator",
|
||||
"subplatform": "android-30",
|
||||
},
|
||||
remote_execution_use_case = "instrumentation-tests",
|
||||
),
|
||||
"static-listing": CommandExecutorConfig(local_enabled = True, remote_enabled = False),
|
||||
},
|
||||
)
|
||||
return inject_test_run_info(ctx, test_info) + [
|
||||
DefaultInfo(),
|
||||
]
|
||||
92
vendor/cxx/tools/buck/prelude/android/android_library.bzl
vendored
Normal file
92
vendor/cxx/tools/buck/prelude/android/android_library.bzl
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//android:android_providers.bzl",
|
||||
"AndroidLibraryIntellijInfo",
|
||||
"AndroidResourceInfo",
|
||||
"merge_android_packageable_info",
|
||||
"merge_exported_android_resource_info",
|
||||
)
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//android:r_dot_java.bzl", "get_dummy_r_dot_java")
|
||||
load("@prelude//java:java_library.bzl", "build_java_library")
|
||||
load("@prelude//java:java_providers.bzl", "create_native_providers", "to_list")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//kotlin:kotlin_library.bzl", "build_kotlin_library")
|
||||
|
||||
def android_library_impl(ctx: "context") -> ["provider"]:
|
||||
packaging_deps = ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.exported_deps + ctx.attrs.runtime_deps
|
||||
if ctx.attrs._build_only_native_code:
|
||||
shared_library_info, cxx_resource_info = create_native_providers(ctx.actions, ctx.label, packaging_deps)
|
||||
return [
|
||||
shared_library_info,
|
||||
cxx_resource_info,
|
||||
# Add an unused default output in case this target is used as an attr.source() anywhere.
|
||||
DefaultInfo(default_outputs = [ctx.actions.write("unused.jar", [])]),
|
||||
]
|
||||
|
||||
java_providers, android_library_intellij_info = build_android_library(ctx)
|
||||
android_providers = [android_library_intellij_info] if android_library_intellij_info else []
|
||||
|
||||
return to_list(java_providers) + [
|
||||
merge_android_packageable_info(
|
||||
ctx.label,
|
||||
ctx.actions,
|
||||
packaging_deps,
|
||||
manifest = ctx.attrs.manifest,
|
||||
),
|
||||
merge_exported_android_resource_info(ctx.attrs.exported_deps),
|
||||
] + android_providers
|
||||
|
||||
def build_android_library(
|
||||
ctx: "context") -> ("JavaProviders", [AndroidLibraryIntellijInfo.type, None]):
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
bootclasspath_entries = [] + ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath
|
||||
additional_classpath_entries = []
|
||||
android_library_intellij_info = None
|
||||
|
||||
dummy_r_dot_java = _get_dummy_r_dot_java(ctx, java_toolchain)
|
||||
if dummy_r_dot_java:
|
||||
additional_classpath_entries.append(dummy_r_dot_java)
|
||||
android_library_intellij_info = AndroidLibraryIntellijInfo(
|
||||
dummy_r_dot_java = dummy_r_dot_java,
|
||||
)
|
||||
|
||||
if ctx.attrs.language != None and ctx.attrs.language.lower() == "kotlin":
|
||||
return build_kotlin_library(
|
||||
ctx,
|
||||
additional_classpath_entries = additional_classpath_entries,
|
||||
bootclasspath_entries = bootclasspath_entries,
|
||||
), android_library_intellij_info
|
||||
else:
|
||||
return build_java_library(
|
||||
ctx,
|
||||
ctx.attrs.srcs,
|
||||
additional_classpath_entries = additional_classpath_entries,
|
||||
bootclasspath_entries = bootclasspath_entries,
|
||||
), android_library_intellij_info
|
||||
|
||||
def _get_dummy_r_dot_java(
|
||||
ctx: "context",
|
||||
java_toolchain: "JavaToolchainInfo") -> ["artifact", None]:
|
||||
android_resources = [resource for resource in filter(None, [
|
||||
x.get(AndroidResourceInfo)
|
||||
for x in ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.provided_deps + (getattr(ctx.attrs, "provided_deps_query", []) or [])
|
||||
]) if resource.res != None]
|
||||
if len(android_resources) == 0:
|
||||
return None
|
||||
|
||||
dummy_r_dot_java_library_info = get_dummy_r_dot_java(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].merge_android_resources[RunInfo],
|
||||
java_toolchain,
|
||||
dedupe(android_resources),
|
||||
ctx.attrs.resource_union_package,
|
||||
)
|
||||
|
||||
return dummy_r_dot_java_library_info.library_output.abi
|
||||
74
vendor/cxx/tools/buck/prelude/android/android_manifest.bzl
vendored
Normal file
74
vendor/cxx/tools/buck/prelude/android/android_manifest.bzl
vendored
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidManifestInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
ROOT_APKMODULE_NAME = "dex"
|
||||
|
||||
def android_manifest_impl(ctx: "context") -> ["provider"]:
|
||||
output, merge_report = generate_android_manifest(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].generate_manifest[RunInfo],
|
||||
ctx.attrs.skeleton,
|
||||
ROOT_APKMODULE_NAME,
|
||||
_get_manifests_from_deps(ctx),
|
||||
{},
|
||||
)
|
||||
|
||||
return [
|
||||
AndroidManifestInfo(manifest = output, merge_report = merge_report),
|
||||
DefaultInfo(default_outputs = [output], other_outputs = [merge_report]),
|
||||
]
|
||||
|
||||
def generate_android_manifest(
|
||||
ctx: "context",
|
||||
generate_manifest: RunInfo.type,
|
||||
manifest_skeleton: "artifact",
|
||||
module_name: str.type,
|
||||
manifests_tset: ["ManifestTSet", None],
|
||||
placeholder_entries: "dict") -> ("artifact", "artifact"):
|
||||
generate_manifest_cmd = cmd_args(generate_manifest)
|
||||
generate_manifest_cmd.add([
|
||||
"--skeleton-manifest",
|
||||
manifest_skeleton,
|
||||
"--module-name",
|
||||
module_name,
|
||||
])
|
||||
|
||||
manifests = manifests_tset.project_as_args("artifacts", ordering = "bfs") if manifests_tset else []
|
||||
library_manifest_paths_file = ctx.actions.write("library_manifest_paths_file", manifests)
|
||||
|
||||
generate_manifest_cmd.add(["--library-manifests-list", library_manifest_paths_file])
|
||||
generate_manifest_cmd.hidden(manifests)
|
||||
|
||||
placeholder_entries_args = cmd_args()
|
||||
for key, val in placeholder_entries.items():
|
||||
placeholder_entries_args.add(cmd_args(key, val, delimiter = " "))
|
||||
placeholder_entries_file = ctx.actions.write("placeholder_entries_file", placeholder_entries_args)
|
||||
|
||||
generate_manifest_cmd.add(["--placeholder-entries-list", placeholder_entries_file])
|
||||
|
||||
output = ctx.actions.declare_output("AndroidManifest.xml")
|
||||
merge_report = ctx.actions.declare_output("merge-report.txt")
|
||||
generate_manifest_cmd.add([
|
||||
"--output",
|
||||
output.as_output(),
|
||||
"--merge-report",
|
||||
merge_report.as_output(),
|
||||
])
|
||||
|
||||
ctx.actions.run(generate_manifest_cmd, category = "generate_manifest")
|
||||
|
||||
return (output, merge_report)
|
||||
|
||||
def _get_manifests_from_deps(ctx: "context") -> ["ManifestTSet", None]:
|
||||
if len(ctx.attrs.deps) == 0:
|
||||
return None
|
||||
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps)
|
||||
return android_packageable_info.manifests
|
||||
108
vendor/cxx/tools/buck/prelude/android/android_prebuilt_aar.bzl
vendored
Normal file
108
vendor/cxx/tools/buck/prelude/android/android_prebuilt_aar.bzl
vendored
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidResourceInfo", "PrebuiltNativeLibraryDir", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_resource.bzl", "aapt2_compile", "extract_package_from_manifest")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load(
|
||||
"@prelude//java:java_providers.bzl",
|
||||
"JavaClasspathEntry",
|
||||
"create_abi",
|
||||
"create_java_library_providers",
|
||||
)
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
|
||||
def android_prebuilt_aar_impl(ctx: "context") -> ["provider"]:
|
||||
manifest = ctx.actions.declare_output("AndroidManifest.xml")
|
||||
all_classes_jar = ctx.actions.declare_output("classes.jar")
|
||||
r_dot_txt = ctx.actions.declare_output("R.txt")
|
||||
res = ctx.actions.declare_output("res")
|
||||
assets = ctx.actions.declare_output("assets")
|
||||
jni = ctx.actions.declare_output("jni")
|
||||
annotation_jars_dir = ctx.actions.declare_output("annotation_jars")
|
||||
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
unpack_aar_tool = android_toolchain.unpack_aar[RunInfo]
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
jar_tool = java_toolchain.jar
|
||||
|
||||
unpack_aar_cmd = [
|
||||
unpack_aar_tool,
|
||||
"--aar",
|
||||
ctx.attrs.aar,
|
||||
"--manifest-path",
|
||||
manifest.as_output(),
|
||||
"--all-classes-jar-path",
|
||||
all_classes_jar.as_output(),
|
||||
"--r-dot-txt-path",
|
||||
r_dot_txt.as_output(),
|
||||
"--res-path",
|
||||
res.as_output(),
|
||||
"--assets-path",
|
||||
assets.as_output(),
|
||||
"--jni-path",
|
||||
jni.as_output(),
|
||||
"--annotation-jars-dir",
|
||||
annotation_jars_dir.as_output(),
|
||||
"--jar-tool",
|
||||
jar_tool,
|
||||
]
|
||||
|
||||
ctx.actions.run(unpack_aar_cmd, category = "android_unpack_aar")
|
||||
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = aapt2_compile(ctx, res, android_toolchain),
|
||||
allow_strings_as_assets_resource_filtering = True,
|
||||
assets = assets,
|
||||
manifest_file = manifest,
|
||||
r_dot_java_package = extract_package_from_manifest(ctx, manifest),
|
||||
res = res,
|
||||
text_symbols = r_dot_txt,
|
||||
)
|
||||
|
||||
abi = None if java_toolchain.is_bootstrap_toolchain else create_abi(ctx.actions, java_toolchain.class_abi_generator, all_classes_jar)
|
||||
|
||||
library_output_classpath_entry = JavaClasspathEntry(
|
||||
full_library = all_classes_jar,
|
||||
abi = abi or all_classes_jar,
|
||||
required_for_source_only_abi = ctx.attrs.required_for_source_only_abi,
|
||||
)
|
||||
|
||||
java_library_info, java_packaging_info, shared_library_info, cxx_resource_info, template_placeholder_info, java_library_intellij_info = create_java_library_providers(
|
||||
ctx = ctx,
|
||||
library_output = library_output_classpath_entry,
|
||||
exported_deps = ctx.attrs.deps,
|
||||
needs_desugar = True,
|
||||
is_prebuilt_jar = True,
|
||||
annotation_jars_dir = annotation_jars_dir,
|
||||
)
|
||||
|
||||
native_library = PrebuiltNativeLibraryDir(
|
||||
raw_target = ctx.label.raw_target(),
|
||||
dir = jni,
|
||||
for_primary_apk = ctx.attrs.use_system_library_loader,
|
||||
is_asset = False,
|
||||
)
|
||||
|
||||
return [
|
||||
java_library_info,
|
||||
java_packaging_info,
|
||||
shared_library_info,
|
||||
cxx_resource_info,
|
||||
template_placeholder_info,
|
||||
java_library_intellij_info,
|
||||
merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps, manifest = manifest, prebuilt_native_library_dir = native_library, resource_info = resource_info),
|
||||
resource_info,
|
||||
DefaultInfo(default_outputs = [all_classes_jar], other_outputs = [
|
||||
manifest,
|
||||
r_dot_txt,
|
||||
res,
|
||||
assets,
|
||||
jni,
|
||||
annotation_jars_dir,
|
||||
]),
|
||||
]
|
||||
283
vendor/cxx/tools/buck/prelude/android/android_providers.bzl
vendored
Normal file
283
vendor/cxx/tools/buck/prelude/android/android_providers.bzl
vendored
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
Aapt2LinkInfo = record(
|
||||
# "APK" containing resources to be used by the Android binary
|
||||
primary_resources_apk = "artifact",
|
||||
# proguard config needed to retain used resources
|
||||
proguard_config_file = "artifact",
|
||||
# R.txt containing all the linked resources
|
||||
r_dot_txt = "artifact",
|
||||
)
|
||||
|
||||
AndroidBinaryNativeLibsInfo = record(
|
||||
apk_under_test_prebuilt_native_library_dirs = ["PrebuiltNativeLibraryDir"],
|
||||
apk_under_test_shared_libraries = ["SharedLibrary"],
|
||||
exopackage_info = ["ExopackageNativeInfo", None],
|
||||
native_lib_assets = ["artifact"],
|
||||
native_libs_for_primary_apk = ["artifact"],
|
||||
unstripped_libs = ["artifact"],
|
||||
)
|
||||
|
||||
AndroidBinaryResourcesInfo = record(
|
||||
# Optional information about resources that should be exopackaged
|
||||
exopackage_info = ["ExopackageResourcesInfo", None],
|
||||
# manifest to be used by the APK
|
||||
manifest = "artifact",
|
||||
# zip containing any strings packaged as assets
|
||||
packaged_string_assets = ["artifact", None],
|
||||
# "APK" containing resources to be used by the Android binary
|
||||
primary_resources_apk = "artifact",
|
||||
# proguard config needed to retain used resources
|
||||
proguard_config_file = "artifact",
|
||||
# R.java jars containing all the linked resources
|
||||
r_dot_javas = ["JavaLibraryInfo"],
|
||||
# directory containing filtered string resources files
|
||||
string_source_map = ["artifact", None],
|
||||
# list of jars that could contain resources that should be packaged into the APK
|
||||
jar_files_that_may_contain_resources = ["artifact"],
|
||||
# The resource infos that are used in this APK
|
||||
unfiltered_resource_infos = ["AndroidResourceInfo"],
|
||||
)
|
||||
|
||||
# Information about an `android_build_config`
|
||||
BuildConfigField = record(
|
||||
type = str.type,
|
||||
name = str.type,
|
||||
value = str.type,
|
||||
)
|
||||
|
||||
AndroidBuildConfigInfo = provider(
|
||||
fields = [
|
||||
"package", # str.type
|
||||
"build_config_fields", # ["BuildConfigField"]
|
||||
],
|
||||
)
|
||||
|
||||
# Information about an `android_manifest`
|
||||
AndroidManifestInfo = provider(
|
||||
fields = [
|
||||
"manifest", # artifact
|
||||
"merge_report", # artifact
|
||||
],
|
||||
)
|
||||
|
||||
AndroidApkInfo = provider(
|
||||
fields = [
|
||||
"apk",
|
||||
"manifest",
|
||||
],
|
||||
)
|
||||
|
||||
AndroidApkUnderTestInfo = provider(
|
||||
fields = [
|
||||
"java_packaging_deps", # ["JavaPackagingDep"]
|
||||
"keystore", # "KeystoreInfo"
|
||||
"manifest_entries", # dict.type
|
||||
"prebuilt_native_library_dirs", # ["PrebuiltNativeLibraryDir"]
|
||||
"platforms", # [str.type]
|
||||
"primary_platform", # str.type
|
||||
"resource_infos", # ["ResourceInfos"]
|
||||
"shared_libraries", # ["SharedLibrary"]
|
||||
],
|
||||
)
|
||||
|
||||
AndroidInstrumentationApkInfo = provider(
|
||||
fields = [
|
||||
"apk_under_test", # "artifact"
|
||||
],
|
||||
)
|
||||
|
||||
CPU_FILTER_TO_ABI_DIRECTORY = {
|
||||
"arm64": "arm64-v8a",
|
||||
"armv7": "armeabi-v7a",
|
||||
"x86": "x86",
|
||||
"x86_64": "x86_64",
|
||||
}
|
||||
|
||||
PrebuiltNativeLibraryDir = record(
|
||||
raw_target = "target_label",
|
||||
dir = "artifact", # contains subdirectories for different ABIs.
|
||||
for_primary_apk = bool.type,
|
||||
is_asset = bool.type,
|
||||
)
|
||||
|
||||
def _artifacts(value: "artifact"):
|
||||
return value
|
||||
|
||||
AndroidBuildConfigInfoTSet = transitive_set()
|
||||
AndroidDepsTSet = transitive_set()
|
||||
ManifestTSet = transitive_set(args_projections = {"artifacts": _artifacts})
|
||||
PrebuiltNativeLibraryDirTSet = transitive_set()
|
||||
ResourceInfoTSet = transitive_set()
|
||||
|
||||
DepsInfo = record(
|
||||
name = "target_label",
|
||||
deps = ["target_label"],
|
||||
)
|
||||
|
||||
AndroidPackageableInfo = provider(
|
||||
fields = [
|
||||
"target_label", # "target_label"
|
||||
"build_config_infos", # ["AndroidBuildConfigInfoTSet", None]
|
||||
"deps", # ["AndroidDepsTSet", None]
|
||||
"manifests", # ["ManifestTSet", None]
|
||||
"prebuilt_native_library_dirs", # ["PrebuiltNativeLibraryDirTSet", None]
|
||||
"resource_infos", # ["AndroidResourceInfoTSet", None]
|
||||
],
|
||||
)
|
||||
|
||||
# Information about an `android_resource`
|
||||
AndroidResourceInfo = provider(
|
||||
fields = [
|
||||
# output of running `aapt2_compile` on the resources, if resources are present
|
||||
"aapt2_compile_output", # ["artifact", None]
|
||||
# if False, then the "res" are not affected by the strings-as-assets resource filter
|
||||
"allow_strings_as_assets_resource_filtering", # bool.type
|
||||
# assets defined by this rule. May be empty
|
||||
"assets", # ["artifact", None]
|
||||
# manifest file used by the resources, if resources are present
|
||||
"manifest_file", # ["artifact", None]
|
||||
# package used for R.java, if resources are present
|
||||
"r_dot_java_package", # ["artifact", None]
|
||||
# resources defined by this rule. May be empty
|
||||
"res", # ["artifact", None]
|
||||
# symbols defined by the resources, if resources are present
|
||||
"text_symbols", # ["artifact", None]
|
||||
],
|
||||
)
|
||||
|
||||
# `AndroidResourceInfos` that are exposed via `exported_deps`
|
||||
ExportedAndroidResourceInfo = provider(
|
||||
fields = [
|
||||
"resource_infos", # ["AndroidResourceInfo"]
|
||||
],
|
||||
)
|
||||
|
||||
ExopackageDexInfo = record(
|
||||
metadata = "artifact",
|
||||
directory = "artifact",
|
||||
)
|
||||
|
||||
ExopackageNativeInfo = record(
|
||||
metadata = "artifact",
|
||||
directory = "artifact",
|
||||
)
|
||||
|
||||
ExopackageResourcesInfo = record(
|
||||
assets = ["artifact", None],
|
||||
assets_hash = ["artifact", None],
|
||||
res = "artifact",
|
||||
res_hash = "artifact",
|
||||
third_party_jar_resources = "artifact",
|
||||
third_party_jar_resources_hash = "artifact",
|
||||
)
|
||||
|
||||
DexFilesInfo = record(
|
||||
primary_dex = "artifact",
|
||||
primary_dex_class_names = ["artifact", None],
|
||||
secondary_dex_dirs = ["artifact"],
|
||||
secondary_dex_exopackage_info = [ExopackageDexInfo.type, None],
|
||||
proguard_text_files_path = ["artifact", None],
|
||||
)
|
||||
|
||||
ExopackageInfo = record(
|
||||
secondary_dex_info = [ExopackageDexInfo.type, None],
|
||||
native_library_info = [ExopackageNativeInfo.type, None],
|
||||
resources_info = [ExopackageResourcesInfo.type, None],
|
||||
)
|
||||
|
||||
AndroidLibraryIntellijInfo = provider(
|
||||
"Information about android library that is required for Intellij project generation",
|
||||
fields = [
|
||||
"dummy_r_dot_java", # ["artifact", None]
|
||||
],
|
||||
)
|
||||
|
||||
def merge_android_packageable_info(
|
||||
label: "label",
|
||||
actions: "actions",
|
||||
deps: ["dependency"],
|
||||
build_config_info: ["AndroidBuildConfigInfo", None] = None,
|
||||
manifest: ["artifact", None] = None,
|
||||
prebuilt_native_library_dir: [PrebuiltNativeLibraryDir.type, None] = None,
|
||||
resource_info: ["AndroidResourceInfo", None] = None) -> "AndroidPackageableInfo":
|
||||
android_packageable_deps = filter(None, [x.get(AndroidPackageableInfo) for x in deps])
|
||||
|
||||
build_config_infos = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.build_config_infos for dep in android_packageable_deps]),
|
||||
build_config_info,
|
||||
AndroidBuildConfigInfoTSet,
|
||||
)
|
||||
|
||||
deps = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.deps for dep in android_packageable_deps]),
|
||||
DepsInfo(
|
||||
name = label.raw_target(),
|
||||
deps = [dep.target_label for dep in android_packageable_deps],
|
||||
),
|
||||
AndroidDepsTSet,
|
||||
)
|
||||
|
||||
manifests = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.manifests for dep in android_packageable_deps]),
|
||||
manifest,
|
||||
ManifestTSet,
|
||||
)
|
||||
|
||||
prebuilt_native_library_dirs = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.prebuilt_native_library_dirs for dep in android_packageable_deps]),
|
||||
prebuilt_native_library_dir,
|
||||
PrebuiltNativeLibraryDirTSet,
|
||||
)
|
||||
|
||||
resource_infos = _get_transitive_set(
|
||||
actions,
|
||||
filter(None, [dep.resource_infos for dep in android_packageable_deps]),
|
||||
resource_info,
|
||||
ResourceInfoTSet,
|
||||
)
|
||||
|
||||
return AndroidPackageableInfo(
|
||||
target_label = label.raw_target(),
|
||||
build_config_infos = build_config_infos,
|
||||
deps = deps,
|
||||
manifests = manifests,
|
||||
prebuilt_native_library_dirs = prebuilt_native_library_dirs,
|
||||
resource_infos = resource_infos,
|
||||
)
|
||||
|
||||
def _get_transitive_set(
|
||||
actions: "actions",
|
||||
children: ["transitive_set"],
|
||||
node: "_a",
|
||||
transitive_set_definition: "transitive_set_definition") -> ["transitive_set", None]:
|
||||
kwargs = {}
|
||||
if children:
|
||||
kwargs["children"] = children
|
||||
if node:
|
||||
kwargs["value"] = node
|
||||
|
||||
return actions.tset(transitive_set_definition, **kwargs) if kwargs else None
|
||||
|
||||
def merge_exported_android_resource_info(
|
||||
exported_deps: ["dependency"]) -> "ExportedAndroidResourceInfo":
|
||||
exported_android_resource_infos = []
|
||||
for exported_dep in exported_deps:
|
||||
exported_resource_info = exported_dep.get(ExportedAndroidResourceInfo)
|
||||
if exported_resource_info:
|
||||
exported_android_resource_infos += exported_resource_info.resource_infos
|
||||
|
||||
android_resource = exported_dep.get(AndroidResourceInfo)
|
||||
if android_resource:
|
||||
exported_android_resource_infos.append(android_resource)
|
||||
|
||||
return ExportedAndroidResourceInfo(resource_infos = dedupe(exported_android_resource_infos))
|
||||
143
vendor/cxx/tools/buck/prelude/android/android_resource.bzl
vendored
Normal file
143
vendor/cxx/tools/buck/prelude/android/android_resource.bzl
vendored
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_providers.bzl", "get_java_packaging_info")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load(":android_providers.bzl", "AndroidResourceInfo", "ExportedAndroidResourceInfo", "merge_android_packageable_info")
|
||||
load(":android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
JAVA_PACKAGE_FILENAME = "java_package.txt"
|
||||
|
||||
def _convert_to_artifact_dir(ctx: "context", attr: ["dependency", "dict", "artifact", None], attr_name: str.type) -> ["artifact", None]:
|
||||
if type(attr) == "dependency":
|
||||
expect(len(attr[DefaultInfo].default_outputs) == 1, "Expect one default output from build dep of attr {}!".format(attr_name))
|
||||
return attr[DefaultInfo].default_outputs[0]
|
||||
elif type(attr) == "dict" and len(attr) > 0:
|
||||
return ctx.actions.symlinked_dir("{}_dir".format(attr_name), attr)
|
||||
else:
|
||||
return attr
|
||||
|
||||
def android_resource_impl(ctx: "context") -> ["provider"]:
|
||||
if ctx.attrs._build_only_native_code:
|
||||
return [DefaultInfo()]
|
||||
|
||||
# TODO(T100007184) filter res/assets by ignored filenames
|
||||
sub_targets = {}
|
||||
providers = []
|
||||
default_outputs = []
|
||||
|
||||
res = _convert_to_artifact_dir(ctx, ctx.attrs.res, "res")
|
||||
assets = _convert_to_artifact_dir(ctx, ctx.attrs.assets, "assets")
|
||||
|
||||
if res:
|
||||
aapt2_compile_output = aapt2_compile(ctx, res, ctx.attrs._android_toolchain[AndroidToolchainInfo])
|
||||
|
||||
sub_targets["aapt2_compile"] = [DefaultInfo(default_outputs = [aapt2_compile_output])]
|
||||
|
||||
r_dot_txt_output = get_text_symbols(ctx, res, ctx.attrs.deps)
|
||||
default_outputs.append(r_dot_txt_output)
|
||||
|
||||
r_dot_java_package = _get_package(ctx, ctx.attrs.package, ctx.attrs.manifest)
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = aapt2_compile_output,
|
||||
allow_strings_as_assets_resource_filtering = not ctx.attrs.has_whitelisted_strings,
|
||||
assets = assets,
|
||||
manifest_file = ctx.attrs.manifest,
|
||||
r_dot_java_package = r_dot_java_package,
|
||||
res = res,
|
||||
text_symbols = r_dot_txt_output,
|
||||
)
|
||||
else:
|
||||
resource_info = AndroidResourceInfo(
|
||||
aapt2_compile_output = None,
|
||||
allow_strings_as_assets_resource_filtering = not ctx.attrs.has_whitelisted_strings,
|
||||
assets = assets,
|
||||
manifest_file = ctx.attrs.manifest,
|
||||
r_dot_java_package = None,
|
||||
res = None,
|
||||
text_symbols = None,
|
||||
)
|
||||
providers.append(resource_info)
|
||||
providers.append(merge_android_packageable_info(ctx.label, ctx.actions, ctx.attrs.deps, manifest = ctx.attrs.manifest, resource_info = resource_info))
|
||||
providers.append(get_java_packaging_info(ctx, ctx.attrs.deps))
|
||||
providers.append(DefaultInfo(default_outputs = default_outputs, sub_targets = sub_targets))
|
||||
|
||||
return providers
|
||||
|
||||
def aapt2_compile(
|
||||
ctx: "context",
|
||||
resources_dir: "artifact",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
skip_crunch_pngs: bool.type = False,
|
||||
identifier: [str.type, None] = None) -> "artifact":
|
||||
aapt2_command = cmd_args(android_toolchain.aapt2)
|
||||
aapt2_command.add("compile")
|
||||
aapt2_command.add("--legacy")
|
||||
if skip_crunch_pngs:
|
||||
aapt2_command.add("--no-crunch")
|
||||
aapt2_command.add(["--dir", resources_dir])
|
||||
aapt2_output = ctx.actions.declare_output("{}_resources.flata".format(identifier) if identifier else "resources.flata")
|
||||
aapt2_command.add("-o", aapt2_output.as_output())
|
||||
|
||||
ctx.actions.run(aapt2_command, category = "aapt2_compile", identifier = identifier)
|
||||
|
||||
return aapt2_output
|
||||
|
||||
def _get_package(ctx: "context", package: [str.type, None], manifest: ["artifact", None]) -> "artifact":
|
||||
if package:
|
||||
return ctx.actions.write(JAVA_PACKAGE_FILENAME, package)
|
||||
else:
|
||||
expect(manifest != None, "if package is not declared then a manifest must be")
|
||||
return extract_package_from_manifest(ctx, manifest)
|
||||
|
||||
def extract_package_from_manifest(ctx: "context", manifest: "artifact") -> "artifact":
|
||||
r_dot_java_package = ctx.actions.declare_output(JAVA_PACKAGE_FILENAME)
|
||||
extract_package_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].manifest_utils[RunInfo])
|
||||
extract_package_cmd.add(["--manifest-path", manifest])
|
||||
extract_package_cmd.add(["--package-output", r_dot_java_package.as_output()])
|
||||
|
||||
ctx.actions.run(extract_package_cmd, category = "android_extract_package")
|
||||
|
||||
return r_dot_java_package
|
||||
|
||||
def get_text_symbols(
|
||||
ctx: "context",
|
||||
res: "artifact",
|
||||
deps: ["dependency"],
|
||||
identifier: [str.type, None] = None):
|
||||
mini_aapt_cmd = cmd_args(ctx.attrs._android_toolchain[AndroidToolchainInfo].mini_aapt[RunInfo])
|
||||
|
||||
mini_aapt_cmd.add(["--resource-paths", res])
|
||||
|
||||
dep_symbol_paths = cmd_args()
|
||||
dep_symbols = _get_dep_symbols(deps)
|
||||
dep_symbol_paths.add(dep_symbols)
|
||||
|
||||
dep_symbol_paths_file, _ = ctx.actions.write("{}_dep_symbol_paths_file".format(identifier) if identifier else "dep_symbol_paths_file", dep_symbol_paths, allow_args = True)
|
||||
|
||||
mini_aapt_cmd.add(["--dep-symbol-paths", dep_symbol_paths_file])
|
||||
mini_aapt_cmd.hidden(dep_symbols)
|
||||
|
||||
text_symbols = ctx.actions.declare_output("{}_R.txt".format(identifier) if identifier else "R.txt")
|
||||
mini_aapt_cmd.add(["--output-path", text_symbols.as_output()])
|
||||
|
||||
ctx.actions.run(mini_aapt_cmd, category = "mini_aapt", identifier = identifier)
|
||||
|
||||
return text_symbols
|
||||
|
||||
def _get_dep_symbols(deps: ["dependency"]) -> ["artifact"]:
|
||||
dep_symbols = []
|
||||
for dep in deps:
|
||||
android_resource_info = dep.get(AndroidResourceInfo)
|
||||
exported_android_resource_info = dep.get(ExportedAndroidResourceInfo)
|
||||
expect(android_resource_info != None or exported_android_resource_info != None, "Dependencies of `android_resource` rules should be `android_resource`s or `android_library`s")
|
||||
if android_resource_info and android_resource_info.text_symbols:
|
||||
dep_symbols.append(android_resource_info.text_symbols)
|
||||
if exported_android_resource_info:
|
||||
dep_symbols += [resource_info.text_symbols for resource_info in exported_android_resource_info.resource_infos if resource_info.text_symbols]
|
||||
|
||||
return dedupe(dep_symbols)
|
||||
50
vendor/cxx/tools/buck/prelude/android/android_toolchain.bzl
vendored
Normal file
50
vendor/cxx/tools/buck/prelude/android/android_toolchain.bzl
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
AndroidPlatformInfo = provider(fields = [
|
||||
"name",
|
||||
])
|
||||
|
||||
AndroidToolchainInfo = provider(fields = [
|
||||
"aapt2",
|
||||
"adb",
|
||||
"aidl",
|
||||
"android_jar",
|
||||
"android_bootclasspath",
|
||||
"apk_builder",
|
||||
"apk_module_graph",
|
||||
"combine_native_library_dirs",
|
||||
"compress_libraries",
|
||||
"d8_command",
|
||||
"exo_resources_rewriter",
|
||||
"exopackage_agent_apk",
|
||||
"filter_dex_class_names",
|
||||
"filter_prebuilt_native_library_dir",
|
||||
"multi_dex_command",
|
||||
"copy_string_resources",
|
||||
"filter_resources",
|
||||
"framework_aidl_file",
|
||||
"generate_build_config",
|
||||
"generate_manifest",
|
||||
"instrumentation_test_runner_classpath",
|
||||
"instrumentation_test_runner_main_class",
|
||||
"manifest_utils",
|
||||
"merge_android_resources",
|
||||
"merge_assets",
|
||||
"merge_third_party_jar_resources",
|
||||
"mini_aapt",
|
||||
"native_libs_as_assets_metadata",
|
||||
"optimized_proguard_config",
|
||||
"package_strings_as_assets",
|
||||
"proguard_config",
|
||||
"proguard_jar",
|
||||
"proguard_max_heap_size",
|
||||
"r_dot_java_weight_factor",
|
||||
"secondary_dex_weight_limit",
|
||||
"unpack_aar",
|
||||
"zipalign",
|
||||
])
|
||||
35
vendor/cxx/tools/buck/prelude/android/apk_genrule.bzl
vendored
Normal file
35
vendor/cxx/tools/buck/prelude/android/apk_genrule.bzl
vendored
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//:genrule.bzl", "process_genrule")
|
||||
load("@prelude//android:android_providers.bzl", "AndroidApkInfo", "AndroidApkUnderTestInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def apk_genrule_impl(ctx: "context") -> ["provider"]:
|
||||
# TODO(T104150125) The underlying APK should not have exopackage enabled
|
||||
input_android_apk_info = ctx.attrs.apk[AndroidApkInfo]
|
||||
expect(input_android_apk_info != None, "'apk' attribute must be an Android APK!")
|
||||
input_android_apk_under_test_info = ctx.attrs.apk[AndroidApkUnderTestInfo]
|
||||
|
||||
env_vars = {
|
||||
"APK": cmd_args(input_android_apk_info.apk),
|
||||
}
|
||||
|
||||
# Like buck1, we ignore the 'out' attribute and construct the output path ourselves.
|
||||
output_apk_name = "{}.apk".format(ctx.label.name)
|
||||
|
||||
genrule_providers = process_genrule(ctx, output_apk_name, None, env_vars)
|
||||
|
||||
expect(len(genrule_providers) == 1 and type(genrule_providers[0]) == DefaultInfo.type, "Expecting just a single DefaultInfo, but got {}".format(genrule_providers))
|
||||
output_apk = genrule_providers[0].default_outputs[0]
|
||||
|
||||
return genrule_providers + [
|
||||
AndroidApkInfo(
|
||||
apk = output_apk,
|
||||
manifest = input_android_apk_info.manifest,
|
||||
),
|
||||
] + filter(None, [input_android_apk_under_test_info])
|
||||
190
vendor/cxx/tools/buck/prelude/android/configuration.bzl
vendored
Normal file
190
vendor/cxx/tools/buck/prelude/android/configuration.bzl
vendored
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "CPU_FILTER_TO_ABI_DIRECTORY")
|
||||
load("@prelude//android:min_sdk_version.bzl", "get_min_sdk_version_constraint_value_name", "get_min_sdk_version_range")
|
||||
|
||||
# FIXME: prelude// should be standalone (not refer to ovr_config//)
|
||||
_REFS = {
|
||||
"arm64": "ovr_config//cpu/constraints:arm64",
|
||||
"armv7": "ovr_config//cpu/constraints:arm32",
|
||||
"build_only_native_code": "fbsource//xplat/buck2/platform/android:build_only_native_code",
|
||||
"building_android_binary": "prelude//os:building_android_binary",
|
||||
"cpu": "ovr_config//cpu/constraints:cpu",
|
||||
"do_not_build_only_native_code": "fbsource//xplat/buck2/platform/android:do_not_build_only_native_code",
|
||||
"maybe_build_only_native_code": "fbsource//xplat/buck2/platform/android:maybe_build_only_native_code",
|
||||
"maybe_building_android_binary": "prelude//os:maybe_building_android_binary",
|
||||
"min_sdk_version": "fbsource//xplat/buck2/platform/android:min_sdk_version",
|
||||
"x86": "ovr_config//cpu/constraints:x86_32",
|
||||
"x86_64": "ovr_config//cpu/constraints:x86_64",
|
||||
}
|
||||
for min_sdk in get_min_sdk_version_range():
|
||||
constraint_value_name = get_min_sdk_version_constraint_value_name(min_sdk)
|
||||
_REFS[constraint_value_name] = "fbsource//xplat/buck2/platform/android:{}".format(constraint_value_name)
|
||||
|
||||
def _cpu_split_transition_instrumentation_test_apk_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu_filters = attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
|
||||
return _cpu_split_transition(platform, refs, cpu_filters, attrs.min_sdk_version, build_only_native_code_on_secondary_platforms = False)
|
||||
|
||||
def _cpu_split_transition_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu_filters = attrs.cpu_filters or CPU_FILTER_TO_ABI_DIRECTORY.keys()
|
||||
do_not_build_only_native_code = refs.do_not_build_only_native_code[ConstraintValueInfo].label in [constraint.label for constraint in platform.configuration.constraints.values()]
|
||||
|
||||
return _cpu_split_transition(platform, refs, cpu_filters, attrs.min_sdk_version, build_only_native_code_on_secondary_platforms = not do_not_build_only_native_code)
|
||||
|
||||
def _cpu_split_transition(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
cpu_filters: [str.type],
|
||||
min_sdk_version: [int.type, None],
|
||||
build_only_native_code_on_secondary_platforms: bool.type) -> {str.type: PlatformInfo.type}:
|
||||
cpu = refs.cpu
|
||||
x86 = refs.x86[ConstraintValueInfo]
|
||||
x86_64 = refs.x86_64[ConstraintValueInfo]
|
||||
armv7 = refs.armv7[ConstraintValueInfo]
|
||||
arm64 = refs.arm64[ConstraintValueInfo]
|
||||
|
||||
cpu_name_to_cpu_constraint = {}
|
||||
for cpu_filter in cpu_filters:
|
||||
if cpu_filter == "x86":
|
||||
cpu_name_to_cpu_constraint["x86"] = x86
|
||||
elif cpu_filter == "armv7":
|
||||
cpu_name_to_cpu_constraint["armv7"] = armv7
|
||||
elif cpu_filter == "x86_64":
|
||||
cpu_name_to_cpu_constraint["x86_64"] = x86_64
|
||||
elif cpu_filter == "arm64":
|
||||
cpu_name_to_cpu_constraint["arm64"] = arm64
|
||||
else:
|
||||
fail("Unexpected cpu_filter: {}".format(cpu_filter))
|
||||
|
||||
base_constraints = {
|
||||
constraint_setting_label: constraint_setting_value
|
||||
for (constraint_setting_label, constraint_setting_value) in platform.configuration.constraints.items()
|
||||
if constraint_setting_label != cpu[ConstraintSettingInfo].label and constraint_setting_label != refs.maybe_build_only_native_code[ConstraintSettingInfo].label
|
||||
}
|
||||
|
||||
base_constraints[refs.maybe_building_android_binary[ConstraintSettingInfo].label] = refs.building_android_binary[ConstraintValueInfo]
|
||||
|
||||
if min_sdk_version:
|
||||
base_constraints[refs.min_sdk_version[ConstraintSettingInfo].label] = _get_min_sdk_constraint_value(min_sdk_version, refs)
|
||||
|
||||
new_configs = {}
|
||||
for platform_name, cpu_constraint in cpu_name_to_cpu_constraint.items():
|
||||
updated_constraints = dict(base_constraints)
|
||||
updated_constraints[refs.cpu[ConstraintSettingInfo].label] = cpu_constraint
|
||||
if len(new_configs) > 0 and build_only_native_code_on_secondary_platforms:
|
||||
updated_constraints[refs.maybe_build_only_native_code[ConstraintSettingInfo].label] = refs.build_only_native_code[ConstraintValueInfo]
|
||||
|
||||
new_configs[platform_name] = PlatformInfo(
|
||||
label = platform_name,
|
||||
configuration = ConfigurationInfo(
|
||||
constraints = updated_constraints,
|
||||
values = platform.configuration.values,
|
||||
),
|
||||
)
|
||||
|
||||
return new_configs
|
||||
|
||||
def _cpu_transition_impl(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type,
|
||||
attrs: struct.type) -> PlatformInfo.type:
|
||||
return _cpu_split_transition_impl(platform, refs, attrs).values()[0]
|
||||
|
||||
cpu_split_transition = transition(
|
||||
impl = _cpu_split_transition_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
split = True,
|
||||
)
|
||||
|
||||
cpu_split_transition_instrumentation_test_apk = transition(
|
||||
impl = _cpu_split_transition_instrumentation_test_apk_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
split = True,
|
||||
)
|
||||
|
||||
# If our deps have been split-transitioned by CPU then we are already analyzing the dependency
|
||||
# graph using the resulting configurations. If there are any other attributes on the same target
|
||||
# that also need to analyze the dependency graph, then we want to use one of the configurations
|
||||
# from the split transition so that we don't end up analyzing the graph again using a different
|
||||
# configuration. This rule just picks the first configuration from the split-transition.
|
||||
#
|
||||
# This is used for the `manifest` attribute of `android_binary`.
|
||||
cpu_transition = transition(
|
||||
impl = _cpu_transition_impl,
|
||||
refs = _REFS,
|
||||
attrs = [
|
||||
"cpu_filters",
|
||||
"min_sdk_version",
|
||||
],
|
||||
)
|
||||
|
||||
def _do_not_build_only_native_code_transition(
|
||||
platform: PlatformInfo.type,
|
||||
refs: struct.type) -> PlatformInfo.type:
|
||||
constraints = dict(platform.configuration.constraints.items())
|
||||
constraints[refs.maybe_build_only_native_code[ConstraintSettingInfo].label] = refs.do_not_build_only_native_code[ConstraintValueInfo]
|
||||
|
||||
return PlatformInfo(
|
||||
label = platform.label,
|
||||
configuration = ConfigurationInfo(
|
||||
constraints = constraints,
|
||||
values = platform.configuration.values,
|
||||
),
|
||||
)
|
||||
|
||||
do_not_build_only_native_code_transition = transition(
|
||||
impl = _do_not_build_only_native_code_transition,
|
||||
refs = {
|
||||
"do_not_build_only_native_code": "fbsource//xplat/buck2/platform/android:do_not_build_only_native_code",
|
||||
"maybe_build_only_native_code": "fbsource//xplat/buck2/platform/android:maybe_build_only_native_code",
|
||||
},
|
||||
)
|
||||
|
||||
def get_deps_by_platform(ctx: "context") -> {str.type: ["dependency"]}:
|
||||
deps_by_platform = {}
|
||||
for dep_dict in ctx.attrs.deps:
|
||||
for platform, dep in dep_dict.items():
|
||||
deps = deps_by_platform.get(platform, [])
|
||||
deps.append(dep)
|
||||
deps_by_platform[platform] = deps
|
||||
|
||||
return deps_by_platform
|
||||
|
||||
def _get_min_sdk_constraint_value(min_sdk_version: int.type, refs: struct.type) -> ConstraintValueInfo.type:
|
||||
constraint_name = get_min_sdk_version_constraint_value_name(min_sdk_version)
|
||||
constraint = getattr(refs, constraint_name, None)
|
||||
if not constraint:
|
||||
fail("Unsupported min_sdk_version {}, please report!".format(min_sdk_version))
|
||||
|
||||
return constraint[ConstraintValueInfo]
|
||||
|
||||
def _is_building_android_binary() -> "selector":
|
||||
return select(
|
||||
{
|
||||
"DEFAULT": False,
|
||||
"prelude//os:building_android_binary": True,
|
||||
},
|
||||
)
|
||||
|
||||
def is_building_android_binary_attr() -> "attribute":
|
||||
return attrs.default_only(attrs.bool(default = _is_building_android_binary()))
|
||||
677
vendor/cxx/tools/buck/prelude/android/dex_rules.bzl
vendored
Normal file
677
vendor/cxx/tools/buck/prelude/android/dex_rules.bzl
vendored
Normal file
|
|
@ -0,0 +1,677 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "DexFilesInfo", "ExopackageDexInfo")
|
||||
load("@prelude//android:voltron.bzl", "ROOT_MODULE", "get_apk_module_graph_info", "get_root_module_only_apk_module_graph_info", "is_root_module")
|
||||
load("@prelude//java:dex.bzl", "get_dex_produced_from_java_library")
|
||||
load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo")
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten")
|
||||
load("@prelude//paths.bzl", "paths")
|
||||
|
||||
# Android builds use a tool called `d8` to compile Java bytecode is DEX (Dalvik EXecutable)
|
||||
# bytecode that runs on Android devices. Our Android builds have two distinct ways of
|
||||
# doing that:
|
||||
# 1) With pre-dexing enabled (this is the most common case for debug builds). That means that
|
||||
# d8 runs on every individual .jar file (to produce a .jar.dex file), and then at the APK
|
||||
# level we run d8 again to combine all the individual .jar.dex files.
|
||||
# 2) With pre-dexing disabled (this is the case if it is explicitly disabled, we are running
|
||||
# proguard, or we preprocess the java classes at the APK level). This means that we run
|
||||
# d8 at the APK level on all the .jar files.
|
||||
#
|
||||
# The .dex files that we package into the APK consist of a single classes.dex "primary DEX"
|
||||
# file, and N secondary DEX files. The classes that are put into the primary DEX are those
|
||||
# that are required at startup, and are specified via `primary_dex_patterns` (classes which
|
||||
# match one of those patterns are put into the primary DEX).
|
||||
#
|
||||
# The primary DEX is always stored in the root directory of the APK as `classes.dex`.
|
||||
#
|
||||
# We have 4 different ways of storing our secondary DEX files, which are specified via the
|
||||
# `dex_compression` attribute:
|
||||
# 1) `raw` compression. This means that we create `classes2.dex`, `classes3.dex`, ...,
|
||||
# `classesN.dex` and store each of them in the root directory of the APK.
|
||||
# 2) `jar` compression. For each secondary DEX file, we put a `classes.dex` entry into a
|
||||
# JAR file, and store it as an asset at `assets/secondary-program-dex-jars/secondary-I.dex.jar`
|
||||
# 3) `xz` compression. This is the same as `jar` compression, except that we run `xz` on the
|
||||
# JAR file to produce `assets/secondary-program-dex-jars/secondary-I.dex.jar.xz`.
|
||||
# 4) `xzs` compression. We do the same as `jar` compression, then concatenate all the jars
|
||||
# together and do `xz` compression on the result to produce a single
|
||||
# `assets/secondary-program-dex-jars/secondary.dex.jar.xzs`.
|
||||
#
|
||||
# For all compression types, we also package a `assets/secondary-program-dex-jars/metadata.txt`,
|
||||
# which has an entry for each secondary DEX file:
|
||||
# <secondary DEX file name> <sha1 hash of secondary DEX> <canary class name>
|
||||
#
|
||||
# A "canary class" is a Java class that we add to every secondary DEX. It is a known class that
|
||||
# can be used for DEX verification when loading the DEX on a device.
|
||||
#
|
||||
# For compression types other than raw, we also include a metadata file per secondary DEX, which
|
||||
# consists of a single line of the form:
|
||||
# jar:<size of secondary dex jar (in bytes)> dex:<size of uncompressed dex file (in bytes)>
|
||||
#
|
||||
# If an APK has Voltron modules, then we produce a separate group of secondary DEX files for each
|
||||
# module, and we put them into `assets/<module_name>` instead of `assets/secondary-program-dex-jars`.
|
||||
# We produce a `metadata.txt` file for each Voltron module.
|
||||
|
||||
_DEX_MERGE_OPTIONS = ["--no-desugar", "--no-optimize"]
|
||||
|
||||
SplitDexMergeConfig = record(
|
||||
dex_compression = str.type,
|
||||
primary_dex_patterns = [str.type],
|
||||
secondary_dex_weight_limit_bytes = int.type,
|
||||
)
|
||||
|
||||
def _get_dex_compression(ctx: "context") -> str.type:
|
||||
is_exopackage_enabled_for_secondary_dexes = "secondary_dex" in ctx.attrs.exopackage_modes
|
||||
default_dex_compression = "jar" if is_exopackage_enabled_for_secondary_dexes else "raw"
|
||||
dex_compression = ctx.attrs.dex_compression or default_dex_compression
|
||||
expect(
|
||||
dex_compression in ["raw", "jar", "xz", "xzs"],
|
||||
"Only 'raw', 'jar', 'xz' and 'xzs' dex compression are supported at this time!",
|
||||
)
|
||||
|
||||
return dex_compression
|
||||
|
||||
def get_split_dex_merge_config(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo") -> "SplitDexMergeConfig":
|
||||
return SplitDexMergeConfig(
|
||||
dex_compression = _get_dex_compression(ctx),
|
||||
primary_dex_patterns = ctx.attrs.primary_dex_patterns,
|
||||
secondary_dex_weight_limit_bytes = (
|
||||
ctx.attrs.secondary_dex_weight_limit or
|
||||
android_toolchain.secondary_dex_weight_limit
|
||||
),
|
||||
)
|
||||
|
||||
def get_single_primary_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_library_jars: ["artifact"],
|
||||
is_optimized: bool.type) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"It doesn't make sense to enable secondary dex exopackage for single dex builds!",
|
||||
)
|
||||
d8_cmd = cmd_args(android_toolchain.d8_command[RunInfo])
|
||||
|
||||
output_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
d8_cmd.add(["--output-dex-file", output_dex_file.as_output()])
|
||||
|
||||
jar_to_dex_file = ctx.actions.write("jar_to_dex_file.txt", java_library_jars)
|
||||
d8_cmd.add(["--files-to-dex-list", jar_to_dex_file])
|
||||
d8_cmd.hidden(java_library_jars)
|
||||
|
||||
d8_cmd.add(["--android-jar", android_toolchain.android_jar])
|
||||
if not is_optimized:
|
||||
d8_cmd.add("--no-optimize")
|
||||
|
||||
ctx.actions.run(d8_cmd, category = "d8", identifier = "{}:{}".format(ctx.label.package, ctx.label.name))
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = output_dex_file,
|
||||
secondary_dex_dirs = [],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = None,
|
||||
)
|
||||
|
||||
def get_multi_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_library_jars_to_owners: {"artifact": "target_label"},
|
||||
primary_dex_patterns: [str.type],
|
||||
proguard_configuration_output_file: ["artifact", None],
|
||||
proguard_mapping_output_file: ["artifact", None],
|
||||
is_optimized: bool.type,
|
||||
apk_module_graph_file: ["artifact", None] = None) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"secondary dex exopackage can only be enabled on pre-dexed builds!",
|
||||
)
|
||||
primary_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
primary_dex_class_names = ctx.actions.declare_output("primary_dex_class_names.txt")
|
||||
root_module_secondary_dex_output_dir = ctx.actions.declare_output("root_module_secondary_dex_output_dir")
|
||||
secondary_dex_dir = ctx.actions.declare_output("secondary_dex_output_dir")
|
||||
|
||||
# dynamic actions are not valid with no input, but it's easier to use the same code regardless,
|
||||
# so just create an empty input.
|
||||
inputs = [apk_module_graph_file] if apk_module_graph_file else [ctx.actions.write("empty_artifact_for_multi_dex_dynamic_action", [])]
|
||||
outputs = [primary_dex_file, primary_dex_class_names, root_module_secondary_dex_output_dir, secondary_dex_dir]
|
||||
|
||||
def do_multi_dex(ctx: "context", artifacts, outputs):
|
||||
apk_module_graph_info = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts) if apk_module_graph_file else get_root_module_only_apk_module_graph_info()
|
||||
target_to_module_mapping_function = apk_module_graph_info.target_to_module_mapping_function
|
||||
module_to_jars = {}
|
||||
for java_library_jar, owner in java_library_jars_to_owners.items():
|
||||
module = target_to_module_mapping_function(str(owner))
|
||||
module_to_jars.setdefault(module, []).append(java_library_jar)
|
||||
|
||||
secondary_dex_dir_srcs = {}
|
||||
for module, jars in module_to_jars.items():
|
||||
multi_dex_cmd = cmd_args(android_toolchain.multi_dex_command[RunInfo])
|
||||
|
||||
if is_root_module(module):
|
||||
multi_dex_cmd.add("--primary-dex", outputs[primary_dex_file].as_output())
|
||||
multi_dex_cmd.add("--primary-dex-patterns-path", ctx.actions.write("primary_dex_patterns", primary_dex_patterns))
|
||||
multi_dex_cmd.add("--primary-dex-class-names", outputs[primary_dex_class_names].as_output())
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", outputs[root_module_secondary_dex_output_dir].as_output())
|
||||
else:
|
||||
secondary_dex_dir_for_module = ctx.actions.declare_output("secondary_dex_output_dir_for_module_{}".format(module))
|
||||
secondary_dex_subdir = secondary_dex_dir_for_module.project(_get_secondary_dex_subdir(module))
|
||||
secondary_dex_dir_srcs[_get_secondary_dex_subdir(module)] = secondary_dex_subdir
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", secondary_dex_dir_for_module.as_output())
|
||||
multi_dex_cmd.add("--module-deps", ctx.actions.write("module_deps_for_{}".format(module), apk_module_graph_info.module_to_module_deps_function(module)))
|
||||
|
||||
multi_dex_cmd.add("--module", module)
|
||||
multi_dex_cmd.add("--canary-class-name", apk_module_graph_info.module_to_canary_class_name_function(module))
|
||||
|
||||
jar_to_dex_file = ctx.actions.write("jars_to_dex_file_for_module_{}.txt".format(module), jars)
|
||||
multi_dex_cmd.add("--files-to-dex-list", jar_to_dex_file)
|
||||
multi_dex_cmd.hidden(jars)
|
||||
|
||||
multi_dex_cmd.add("--android-jar", android_toolchain.android_jar)
|
||||
if not is_optimized:
|
||||
multi_dex_cmd.add("--no-optimize")
|
||||
|
||||
if proguard_configuration_output_file:
|
||||
multi_dex_cmd.add("--proguard-configuration-file", proguard_configuration_output_file)
|
||||
multi_dex_cmd.add("--proguard-mapping-file", proguard_mapping_output_file)
|
||||
|
||||
multi_dex_cmd.add("--compression", _get_dex_compression(ctx))
|
||||
multi_dex_cmd.add("--xz-compression-level", str(ctx.attrs.xz_compression_level))
|
||||
if ctx.attrs.minimize_primary_dex_size:
|
||||
multi_dex_cmd.add("--minimize-primary-dex")
|
||||
|
||||
ctx.actions.run(multi_dex_cmd, category = "multi_dex", identifier = "{}:{}_module_{}".format(ctx.label.package, ctx.label.name, module))
|
||||
|
||||
ctx.actions.symlinked_dir(outputs[secondary_dex_dir], secondary_dex_dir_srcs)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = inputs, inputs = [], outputs = outputs, f = do_multi_dex)
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = primary_dex_file,
|
||||
secondary_dex_dirs = [root_module_secondary_dex_output_dir, secondary_dex_dir],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = primary_dex_class_names,
|
||||
)
|
||||
|
||||
def merge_to_single_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
pre_dexed_libs: ["DexLibraryInfo"]) -> "DexFilesInfo":
|
||||
expect(
|
||||
not _is_exopackage_enabled_for_secondary_dex(ctx),
|
||||
"It doesn't make sense to enable secondary dex exopackage for single dex builds!",
|
||||
)
|
||||
output_dex_file = ctx.actions.declare_output("classes.dex")
|
||||
pre_dexed_artifacts_to_dex_file = ctx.actions.declare_output("pre_dexed_artifacts_to_dex_file.txt")
|
||||
pre_dexed_artifacts = [pre_dexed_lib.dex for pre_dexed_lib in pre_dexed_libs if pre_dexed_lib.dex != None]
|
||||
_merge_dexes(ctx, android_toolchain, output_dex_file, pre_dexed_artifacts, pre_dexed_artifacts_to_dex_file)
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = output_dex_file,
|
||||
secondary_dex_dirs = [],
|
||||
secondary_dex_exopackage_info = None,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = None,
|
||||
)
|
||||
|
||||
DexInputWithSpecifiedClasses = record(
|
||||
lib = "DexLibraryInfo",
|
||||
dex_class_names = [str.type],
|
||||
)
|
||||
|
||||
DexInputWithClassNamesFile = record(
|
||||
lib = "DexLibraryInfo",
|
||||
filtered_class_names_file = "artifact",
|
||||
)
|
||||
|
||||
# When using jar compression, the secondary dex directory consists of N secondary dex jars, each
|
||||
# of which has a corresponding .meta file (the secondary_dex_metadata_file) containing a single
|
||||
# line of the form:
|
||||
# jar:<size of secondary dex jar (in bytes)> dex:<size of uncompressed dex file (in bytes)>
|
||||
#
|
||||
# It also contains a metadata.txt file, which consists on N lines, one for each secondary dex
|
||||
# jar. Those lines consist of:
|
||||
# <secondary dex file name> <sha1 hash of secondary dex> <canary class>
|
||||
#
|
||||
# We write the line that needs to be added to metadata.txt for this secondary dex jar to
|
||||
# secondary_dex_metadata_line, and we use the secondary_dex_canary_class_name for the
|
||||
# <canary class>.
|
||||
#
|
||||
# When we have finished building all of the secondary dexes, we read each of the
|
||||
# secondary_dex_metadata_line artifacts and write them to a single metadata.txt file.
|
||||
# We do that for raw compression too, since it also has a metadata.txt file.
|
||||
SecondaryDexMetadataConfig = record(
|
||||
secondary_dex_compression = str.type,
|
||||
secondary_dex_metadata_path = [str.type, None],
|
||||
secondary_dex_metadata_file = ["artifact", None],
|
||||
secondary_dex_metadata_line = "artifact",
|
||||
secondary_dex_canary_class_name = str.type,
|
||||
)
|
||||
|
||||
def _get_secondary_dex_jar_metadata_config(
|
||||
actions: "actions",
|
||||
secondary_dex_path: str.type,
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
index: int.type) -> SecondaryDexMetadataConfig.type:
|
||||
secondary_dex_metadata_path = secondary_dex_path + ".meta"
|
||||
return SecondaryDexMetadataConfig(
|
||||
secondary_dex_compression = "jar",
|
||||
secondary_dex_metadata_path = secondary_dex_metadata_path,
|
||||
secondary_dex_metadata_file = actions.declare_output(secondary_dex_metadata_path),
|
||||
secondary_dex_metadata_line = actions.declare_output("metadata_line_artifacts/{}/{}".format(module, index + 1)),
|
||||
secondary_dex_canary_class_name = _get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index + 1),
|
||||
)
|
||||
|
||||
def _get_secondary_dex_raw_metadata_config(
|
||||
actions: "actions",
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
index: int.type) -> SecondaryDexMetadataConfig.type:
|
||||
return SecondaryDexMetadataConfig(
|
||||
secondary_dex_compression = "raw",
|
||||
secondary_dex_metadata_path = None,
|
||||
secondary_dex_metadata_file = None,
|
||||
secondary_dex_metadata_line = actions.declare_output("metadata_line_artifacts/{}/{}".format(module, index + 1)),
|
||||
secondary_dex_canary_class_name = _get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index + 1),
|
||||
)
|
||||
|
||||
def _get_filter_dex_batch_size() -> int.type:
|
||||
return 100
|
||||
|
||||
def _filter_pre_dexed_libs(
|
||||
actions: "actions",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
primary_dex_patterns_file: "artifact",
|
||||
pre_dexed_libs: ["DexLibraryInfo"],
|
||||
batch_number: int.type) -> [DexInputWithClassNamesFile.type]:
|
||||
pre_dexed_lib_with_class_names_files = []
|
||||
for pre_dexed_lib in pre_dexed_libs:
|
||||
class_names = pre_dexed_lib.class_names
|
||||
id = "{}_{}_{}".format(class_names.owner.package, class_names.owner.name, class_names.short_path)
|
||||
filtered_class_names_file = actions.declare_output("primary_dex_class_names_for_{}".format(id))
|
||||
pre_dexed_lib_with_class_names_files.append(
|
||||
DexInputWithClassNamesFile(lib = pre_dexed_lib, filtered_class_names_file = filtered_class_names_file),
|
||||
)
|
||||
|
||||
filter_dex_cmd = cmd_args([
|
||||
android_toolchain.filter_dex_class_names[RunInfo],
|
||||
"--primary-dex-patterns",
|
||||
primary_dex_patterns_file,
|
||||
"--class-names",
|
||||
[x.lib.class_names for x in pre_dexed_lib_with_class_names_files],
|
||||
"--output",
|
||||
[x.filtered_class_names_file.as_output() for x in pre_dexed_lib_with_class_names_files],
|
||||
])
|
||||
actions.run(filter_dex_cmd, category = "filter_dex", identifier = "batch_{}".format(batch_number))
|
||||
|
||||
return pre_dexed_lib_with_class_names_files
|
||||
|
||||
_SortedPreDexedInputs = record(
|
||||
module = str.type,
|
||||
primary_dex_inputs = [DexInputWithSpecifiedClasses.type],
|
||||
secondary_dex_inputs = [[DexInputWithSpecifiedClasses.type]],
|
||||
)
|
||||
|
||||
def merge_to_split_dex(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
pre_dexed_libs: ["DexLibraryInfo"],
|
||||
split_dex_merge_config: "SplitDexMergeConfig",
|
||||
apk_module_graph_file: ["artifact", None] = None) -> "DexFilesInfo":
|
||||
is_exopackage_enabled_for_secondary_dex = _is_exopackage_enabled_for_secondary_dex(ctx)
|
||||
if is_exopackage_enabled_for_secondary_dex:
|
||||
expect(
|
||||
split_dex_merge_config.dex_compression == "jar",
|
||||
"Exopackage can only be enabled for secondary dexes when the dex compression is 'jar', but the dex compression is '{}'".format(split_dex_merge_config.dex_compression),
|
||||
)
|
||||
primary_dex_patterns_file = ctx.actions.write("primary_dex_patterns_file", split_dex_merge_config.primary_dex_patterns)
|
||||
|
||||
pre_dexed_lib_with_class_names_files = []
|
||||
|
||||
batch_size = _get_filter_dex_batch_size()
|
||||
for (batch_number, start_index) in enumerate(range(0, len(pre_dexed_libs), batch_size)):
|
||||
end_index = min(start_index + batch_size, len(pre_dexed_libs))
|
||||
pre_dexed_lib_with_class_names_files.extend(
|
||||
_filter_pre_dexed_libs(
|
||||
ctx.actions,
|
||||
android_toolchain,
|
||||
primary_dex_patterns_file,
|
||||
pre_dexed_libs[start_index:end_index],
|
||||
batch_number,
|
||||
),
|
||||
)
|
||||
|
||||
input_artifacts = flatten([[
|
||||
input.lib.dex,
|
||||
input.lib.weight_estimate,
|
||||
input.filtered_class_names_file,
|
||||
] for input in pre_dexed_lib_with_class_names_files]) + ([apk_module_graph_file] if apk_module_graph_file else [])
|
||||
primary_dex_artifact_list = ctx.actions.declare_output("pre_dexed_artifacts_for_primary_dex.txt")
|
||||
primary_dex_output = ctx.actions.declare_output("classes.dex")
|
||||
primary_dex_class_names_list = ctx.actions.declare_output("primary_dex_class_names_list.txt")
|
||||
root_module_secondary_dexes_dir = ctx.actions.declare_output("root_module_secondary_dexes_dir")
|
||||
root_module_secondary_dexes_subdir = root_module_secondary_dexes_dir.project(_get_secondary_dex_subdir(ROOT_MODULE))
|
||||
root_module_secondary_dexes_metadata = root_module_secondary_dexes_dir.project(paths.join(_get_secondary_dex_subdir(ROOT_MODULE), "metadata.txt"))
|
||||
non_root_module_secondary_dexes_dir = ctx.actions.declare_output("non_root_module_secondary_dexes_dir")
|
||||
|
||||
outputs = [primary_dex_output, primary_dex_artifact_list, primary_dex_class_names_list, root_module_secondary_dexes_dir, non_root_module_secondary_dexes_dir]
|
||||
|
||||
def merge_pre_dexed_libs(ctx: "context", artifacts, outputs):
|
||||
apk_module_graph_info = get_apk_module_graph_info(ctx, apk_module_graph_file, artifacts) if apk_module_graph_file else get_root_module_only_apk_module_graph_info()
|
||||
module_to_canary_class_name_function = apk_module_graph_info.module_to_canary_class_name_function
|
||||
sorted_pre_dexed_inputs = _sort_pre_dexed_files(
|
||||
ctx,
|
||||
artifacts,
|
||||
pre_dexed_lib_with_class_names_files,
|
||||
split_dex_merge_config,
|
||||
get_module_from_target = apk_module_graph_info.target_to_module_mapping_function,
|
||||
module_to_canary_class_name_function = module_to_canary_class_name_function,
|
||||
)
|
||||
|
||||
root_module_secondary_dexes_for_symlinking = {}
|
||||
non_root_module_secondary_dexes_for_symlinking = {}
|
||||
metadata_line_artifacts_by_module = {}
|
||||
metadata_dot_txt_files_by_module = {}
|
||||
|
||||
for sorted_pre_dexed_input in sorted_pre_dexed_inputs:
|
||||
module = sorted_pre_dexed_input.module
|
||||
secondary_dexes_for_symlinking = root_module_secondary_dexes_for_symlinking if is_root_module(module) else non_root_module_secondary_dexes_for_symlinking
|
||||
primary_dex_inputs = sorted_pre_dexed_input.primary_dex_inputs
|
||||
pre_dexed_artifacts = [primary_dex_input.lib.dex for primary_dex_input in primary_dex_inputs if primary_dex_input.lib.dex]
|
||||
if pre_dexed_artifacts:
|
||||
expect(is_root_module(module), "module {} should not have a primary dex!".format(module))
|
||||
ctx.actions.write(
|
||||
outputs[primary_dex_class_names_list].as_output(),
|
||||
flatten([primary_dex_input.dex_class_names for primary_dex_input in primary_dex_inputs]),
|
||||
)
|
||||
|
||||
_merge_dexes(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
outputs[primary_dex_output],
|
||||
pre_dexed_artifacts,
|
||||
outputs[primary_dex_artifact_list],
|
||||
class_names_to_include = primary_dex_class_names_list,
|
||||
)
|
||||
else:
|
||||
expect(
|
||||
not is_root_module(module),
|
||||
"No primary dex classes were specified! Please add primary_dex_patterns to ensure that at least one class exists in the primary dex.",
|
||||
)
|
||||
|
||||
secondary_dex_inputs = sorted_pre_dexed_input.secondary_dex_inputs
|
||||
raw_secondary_dexes_for_compressing = {}
|
||||
for i in range(len(secondary_dex_inputs)):
|
||||
if split_dex_merge_config.dex_compression == "jar" or split_dex_merge_config.dex_compression == "raw":
|
||||
if split_dex_merge_config.dex_compression == "jar":
|
||||
secondary_dex_path = _get_jar_secondary_dex_path(i, module)
|
||||
secondary_dex_metadata_config = _get_secondary_dex_jar_metadata_config(ctx.actions, secondary_dex_path, module, module_to_canary_class_name_function, i)
|
||||
secondary_dexes_for_symlinking[secondary_dex_metadata_config.secondary_dex_metadata_path] = secondary_dex_metadata_config.secondary_dex_metadata_file
|
||||
else:
|
||||
secondary_dex_path = _get_raw_secondary_dex_path(i, module)
|
||||
secondary_dex_metadata_config = _get_secondary_dex_raw_metadata_config(ctx.actions, module, module_to_canary_class_name_function, i)
|
||||
|
||||
secondary_dex_output = ctx.actions.declare_output(secondary_dex_path)
|
||||
secondary_dexes_for_symlinking[secondary_dex_path] = secondary_dex_output
|
||||
metadata_line_artifacts_by_module.setdefault(module, []).append(secondary_dex_metadata_config.secondary_dex_metadata_line)
|
||||
else:
|
||||
secondary_dex_name = _get_raw_secondary_dex_name(i, module)
|
||||
secondary_dex_output = ctx.actions.declare_output("{}/{}".format(module, secondary_dex_name))
|
||||
raw_secondary_dexes_for_compressing[secondary_dex_name] = secondary_dex_output
|
||||
secondary_dex_metadata_config = None
|
||||
|
||||
secondary_dex_artifact_list = ctx.actions.declare_output("pre_dexed_artifacts_for_secondary_dex_{}_for_module_{}.txt".format(i + 2, module))
|
||||
secondary_dex_class_list = ctx.actions.write(
|
||||
"class_list_for_secondary_dex_{}_for_module_{}.txt".format(i + 2, module),
|
||||
flatten([secondary_dex_input.dex_class_names for secondary_dex_input in secondary_dex_inputs[i]]),
|
||||
)
|
||||
pre_dexed_artifacts = [secondary_dex_input.lib.dex for secondary_dex_input in secondary_dex_inputs[i] if secondary_dex_input.lib.dex]
|
||||
_merge_dexes(
|
||||
ctx,
|
||||
android_toolchain,
|
||||
secondary_dex_output,
|
||||
pre_dexed_artifacts,
|
||||
secondary_dex_artifact_list,
|
||||
class_names_to_include = secondary_dex_class_list,
|
||||
secondary_dex_metadata_config = secondary_dex_metadata_config,
|
||||
)
|
||||
|
||||
if split_dex_merge_config.dex_compression == "jar" or split_dex_merge_config.dex_compression == "raw":
|
||||
metadata_dot_txt_path = "{}/metadata.txt".format(_get_secondary_dex_subdir(module))
|
||||
metadata_dot_txt_file = ctx.actions.declare_output(metadata_dot_txt_path)
|
||||
secondary_dexes_for_symlinking[metadata_dot_txt_path] = metadata_dot_txt_file
|
||||
metadata_dot_txt_files_by_module[module] = metadata_dot_txt_file
|
||||
else:
|
||||
raw_secondary_dexes_dir = ctx.actions.symlinked_dir("raw_secondary_dexes_dir_for_module_{}".format(module), raw_secondary_dexes_for_compressing)
|
||||
secondary_dex_dir_for_module = ctx.actions.declare_output("secondary_dexes_dir_for_{}".format(module))
|
||||
secondary_dex_subdir = secondary_dex_dir_for_module.project(_get_secondary_dex_subdir(module))
|
||||
|
||||
multi_dex_cmd = cmd_args(android_toolchain.multi_dex_command[RunInfo])
|
||||
multi_dex_cmd.add("--secondary-dex-output-dir", secondary_dex_dir_for_module.as_output())
|
||||
multi_dex_cmd.add("--raw-secondary-dexes-dir", raw_secondary_dexes_dir)
|
||||
multi_dex_cmd.add("--compression", _get_dex_compression(ctx))
|
||||
multi_dex_cmd.add("--xz-compression-level", str(ctx.attrs.xz_compression_level))
|
||||
multi_dex_cmd.add("--module", module)
|
||||
multi_dex_cmd.add("--canary-class-name", module_to_canary_class_name_function(module))
|
||||
if not is_root_module(module):
|
||||
multi_dex_cmd.add("--module-deps", ctx.actions.write("module_deps_for_{}".format(module), apk_module_graph_info.module_to_module_deps_function(module)))
|
||||
|
||||
ctx.actions.run(multi_dex_cmd, category = "multi_dex_from_raw_dexes", identifier = "{}:{}_module_{}".format(ctx.label.package, ctx.label.name, module))
|
||||
|
||||
secondary_dexes_for_symlinking[_get_secondary_dex_subdir(module)] = secondary_dex_subdir
|
||||
|
||||
if metadata_dot_txt_files_by_module:
|
||||
def write_metadata_dot_txts(ctx: "context", artifacts, outputs):
|
||||
for voltron_module, metadata_dot_txt in metadata_dot_txt_files_by_module.items():
|
||||
metadata_line_artifacts = metadata_line_artifacts_by_module[voltron_module]
|
||||
expect(metadata_line_artifacts != None, "Should have metadata lines!")
|
||||
|
||||
metadata_lines = [".id {}".format(voltron_module)]
|
||||
metadata_lines.extend([".requires {}".format(module_dep) for module_dep in apk_module_graph_info.module_to_module_deps_function(voltron_module)])
|
||||
if split_dex_merge_config.dex_compression == "raw" and is_root_module(voltron_module):
|
||||
metadata_lines.append(".root_relative")
|
||||
for metadata_line_artifact in metadata_line_artifacts:
|
||||
metadata_lines.append(artifacts[metadata_line_artifact].read_string().strip())
|
||||
ctx.actions.write(outputs[metadata_dot_txt], metadata_lines)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = flatten(metadata_line_artifacts_by_module.values()), inputs = [], outputs = metadata_dot_txt_files_by_module.values(), f = write_metadata_dot_txts)
|
||||
|
||||
ctx.actions.symlinked_dir(
|
||||
outputs[root_module_secondary_dexes_dir],
|
||||
root_module_secondary_dexes_for_symlinking,
|
||||
)
|
||||
ctx.actions.symlinked_dir(
|
||||
outputs[non_root_module_secondary_dexes_dir],
|
||||
non_root_module_secondary_dexes_for_symlinking,
|
||||
)
|
||||
|
||||
ctx.actions.dynamic_output(dynamic = input_artifacts, inputs = [], outputs = outputs, f = merge_pre_dexed_libs)
|
||||
|
||||
if is_exopackage_enabled_for_secondary_dex:
|
||||
secondary_dex_dirs = [non_root_module_secondary_dexes_dir]
|
||||
secondary_dex_exopackage_info = ExopackageDexInfo(
|
||||
metadata = root_module_secondary_dexes_metadata,
|
||||
directory = root_module_secondary_dexes_subdir,
|
||||
)
|
||||
else:
|
||||
secondary_dex_dirs = [root_module_secondary_dexes_dir, non_root_module_secondary_dexes_dir]
|
||||
secondary_dex_exopackage_info = None
|
||||
|
||||
return DexFilesInfo(
|
||||
primary_dex = primary_dex_output,
|
||||
secondary_dex_dirs = secondary_dex_dirs,
|
||||
secondary_dex_exopackage_info = secondary_dex_exopackage_info,
|
||||
proguard_text_files_path = None,
|
||||
primary_dex_class_names = primary_dex_class_names_list,
|
||||
)
|
||||
|
||||
def _merge_dexes(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
output_dex_file: "artifact",
|
||||
pre_dexed_artifacts: ["artifact"],
|
||||
pre_dexed_artifacts_file: "artifact",
|
||||
class_names_to_include: ["artifact", None] = None,
|
||||
secondary_output_dex_file: ["artifact", None] = None,
|
||||
secondary_dex_metadata_config: [SecondaryDexMetadataConfig.type, None] = None):
|
||||
d8_cmd = cmd_args(android_toolchain.d8_command[RunInfo])
|
||||
d8_cmd.add(["--output-dex-file", output_dex_file.as_output()])
|
||||
|
||||
pre_dexed_artifacts_to_dex_file = ctx.actions.write(pre_dexed_artifacts_file.as_output(), pre_dexed_artifacts)
|
||||
d8_cmd.add(["--files-to-dex-list", pre_dexed_artifacts_to_dex_file])
|
||||
d8_cmd.hidden(pre_dexed_artifacts)
|
||||
|
||||
d8_cmd.add(["--android-jar", android_toolchain.android_jar])
|
||||
d8_cmd.add(_DEX_MERGE_OPTIONS)
|
||||
|
||||
if class_names_to_include:
|
||||
d8_cmd.add(["--primary-dex-class-names-path", class_names_to_include])
|
||||
|
||||
if secondary_output_dex_file:
|
||||
d8_cmd.add(["--secondary-output-dex-file", secondary_output_dex_file.as_output()])
|
||||
|
||||
if secondary_dex_metadata_config:
|
||||
d8_cmd.add(["--secondary-dex-compression", secondary_dex_metadata_config.secondary_dex_compression])
|
||||
if secondary_dex_metadata_config.secondary_dex_metadata_file:
|
||||
d8_cmd.add(["--secondary-dex-metadata-file", secondary_dex_metadata_config.secondary_dex_metadata_file.as_output()])
|
||||
d8_cmd.add(["--secondary-dex-metadata-line", secondary_dex_metadata_config.secondary_dex_metadata_line.as_output()])
|
||||
d8_cmd.add(["--secondary-dex-canary-class-name", secondary_dex_metadata_config.secondary_dex_canary_class_name])
|
||||
|
||||
ctx.actions.run(
|
||||
d8_cmd,
|
||||
category = "d8",
|
||||
identifier = "{}:{} {}".format(ctx.label.package, ctx.label.name, output_dex_file.short_path),
|
||||
)
|
||||
|
||||
def _sort_pre_dexed_files(
|
||||
ctx: "context",
|
||||
artifacts,
|
||||
pre_dexed_lib_with_class_names_files: ["DexInputWithClassNamesFile"],
|
||||
split_dex_merge_config: "SplitDexMergeConfig",
|
||||
get_module_from_target: "function",
|
||||
module_to_canary_class_name_function: "function") -> [_SortedPreDexedInputs.type]:
|
||||
sorted_pre_dexed_inputs_map = {}
|
||||
current_secondary_dex_size_map = {}
|
||||
current_secondary_dex_inputs_map = {}
|
||||
for pre_dexed_lib_with_class_names_file in pre_dexed_lib_with_class_names_files:
|
||||
pre_dexed_lib = pre_dexed_lib_with_class_names_file.lib
|
||||
module = get_module_from_target(str(pre_dexed_lib.dex.owner.raw_target()))
|
||||
primary_dex_data, secondary_dex_data = artifacts[pre_dexed_lib_with_class_names_file.filtered_class_names_file].read_string().split(";")
|
||||
primary_dex_class_names = primary_dex_data.split(",") if primary_dex_data else []
|
||||
secondary_dex_class_names = secondary_dex_data.split(",") if secondary_dex_data else []
|
||||
|
||||
module_pre_dexed_inputs = sorted_pre_dexed_inputs_map.setdefault(module, _SortedPreDexedInputs(
|
||||
module = module,
|
||||
primary_dex_inputs = [],
|
||||
secondary_dex_inputs = [],
|
||||
))
|
||||
|
||||
primary_dex_inputs = module_pre_dexed_inputs.primary_dex_inputs
|
||||
secondary_dex_inputs = module_pre_dexed_inputs.secondary_dex_inputs
|
||||
|
||||
if len(primary_dex_class_names) > 0:
|
||||
expect(
|
||||
is_root_module(module),
|
||||
"Non-root modules should not have anything that belongs in the primary dex, " +
|
||||
"but {} is assigned to module {} and has the following class names in the primary dex: {}\n".format(
|
||||
pre_dexed_lib.dex.owner,
|
||||
module,
|
||||
"\n".join(primary_dex_class_names),
|
||||
),
|
||||
)
|
||||
primary_dex_inputs.append(
|
||||
DexInputWithSpecifiedClasses(lib = pre_dexed_lib, dex_class_names = primary_dex_class_names),
|
||||
)
|
||||
|
||||
if len(secondary_dex_class_names) > 0:
|
||||
weight_estimate = int(artifacts[pre_dexed_lib.weight_estimate].read_string().strip())
|
||||
current_secondary_dex_size = current_secondary_dex_size_map.get(module, 0)
|
||||
if current_secondary_dex_size + weight_estimate > split_dex_merge_config.secondary_dex_weight_limit_bytes:
|
||||
current_secondary_dex_size = 0
|
||||
current_secondary_dex_inputs_map[module] = []
|
||||
|
||||
current_secondary_dex_inputs = current_secondary_dex_inputs_map.setdefault(module, [])
|
||||
if len(current_secondary_dex_inputs) == 0:
|
||||
canary_class_dex_input = _create_canary_class(
|
||||
ctx,
|
||||
len(secondary_dex_inputs) + 1,
|
||||
module,
|
||||
module_to_canary_class_name_function,
|
||||
ctx.attrs._dex_toolchain[DexToolchainInfo],
|
||||
)
|
||||
current_secondary_dex_inputs.append(canary_class_dex_input)
|
||||
secondary_dex_inputs.append(current_secondary_dex_inputs)
|
||||
|
||||
current_secondary_dex_size_map[module] = current_secondary_dex_size + weight_estimate
|
||||
current_secondary_dex_inputs.append(
|
||||
DexInputWithSpecifiedClasses(lib = pre_dexed_lib, dex_class_names = secondary_dex_class_names),
|
||||
)
|
||||
|
||||
return sorted_pre_dexed_inputs_map.values()
|
||||
|
||||
def _get_raw_secondary_dex_name(index: int.type, module: str.type) -> str.type:
|
||||
# Root module begins at 2 (primary classes.dex is 1)
|
||||
# Non-root module begins at 1 (classes.dex)
|
||||
if is_root_module(module):
|
||||
return "classes{}.dex".format(index + 2)
|
||||
elif index == 0:
|
||||
return "classes.dex".format(module)
|
||||
else:
|
||||
return "classes{}.dex".format(module, index + 1)
|
||||
|
||||
def _get_raw_secondary_dex_path(index: int.type, module: str.type):
|
||||
if is_root_module(module):
|
||||
return _get_raw_secondary_dex_name(index, module)
|
||||
else:
|
||||
return "assets/{}/{}".format(module, _get_raw_secondary_dex_name(index, module))
|
||||
|
||||
def _get_jar_secondary_dex_path(index: int.type, module: str.type):
|
||||
return "{}/{}-{}.dex.jar".format(
|
||||
_get_secondary_dex_subdir(module),
|
||||
"secondary" if is_root_module(module) else module,
|
||||
index + 1,
|
||||
)
|
||||
|
||||
def _get_secondary_dex_subdir(module: str.type):
|
||||
return "assets/{}".format("secondary-program-dex-jars" if is_root_module(module) else module)
|
||||
|
||||
# We create "canary" classes and add them to each secondary dex jar to ensure each jar has a class
|
||||
# that can be safely loaded on any system. This class is used during secondary dex verification.
|
||||
_CANARY_FULLY_QUALIFIED_CLASS_NAME_TEMPLATE = "{}.dex{}.Canary"
|
||||
_CANARY_FILE_NAME_TEMPLATE = "canary_classes/{}/dex{}/Canary.java"
|
||||
_CANARY_CLASS_PACKAGE_TEMPLATE = "package {}.dex{};\n"
|
||||
_CANARY_CLASS_INTERFACE_DEFINITION = "public interface Canary {}"
|
||||
|
||||
def _create_canary_class(
|
||||
ctx: "context",
|
||||
index: int.type,
|
||||
module: str.type,
|
||||
module_to_canary_class_name_function: "function",
|
||||
dex_toolchain: DexToolchainInfo.type) -> DexInputWithSpecifiedClasses.type:
|
||||
prefix = module_to_canary_class_name_function(module)
|
||||
canary_class_java_file = ctx.actions.write(_CANARY_FILE_NAME_TEMPLATE.format(prefix, index), [_CANARY_CLASS_PACKAGE_TEMPLATE.format(prefix, index), _CANARY_CLASS_INTERFACE_DEFINITION])
|
||||
canary_class_jar = ctx.actions.declare_output("canary_classes/{}/canary_jar_{}.jar".format(prefix, index))
|
||||
compile_to_jar(ctx, [canary_class_java_file], output = canary_class_jar, actions_prefix = "{}_canary_class{}".format(prefix, index))
|
||||
|
||||
dex_library_info = get_dex_produced_from_java_library(ctx, dex_toolchain = dex_toolchain, jar_to_dex = canary_class_jar)
|
||||
|
||||
return DexInputWithSpecifiedClasses(
|
||||
lib = dex_library_info,
|
||||
dex_class_names = [_get_fully_qualified_canary_class_name(module, module_to_canary_class_name_function, index).replace(".", "/") + ".class"],
|
||||
)
|
||||
|
||||
def _get_fully_qualified_canary_class_name(module: str.type, module_to_canary_class_name_function: "function", index: int.type) -> str.type:
|
||||
prefix = module_to_canary_class_name_function(module)
|
||||
return _CANARY_FULLY_QUALIFIED_CLASS_NAME_TEMPLATE.format(prefix, index)
|
||||
|
||||
def _is_exopackage_enabled_for_secondary_dex(ctx: "context") -> bool.type:
|
||||
return "secondary_dex" in getattr(ctx.attrs, "exopackage_modes", [])
|
||||
27
vendor/cxx/tools/buck/prelude/android/exopackage.bzl
vendored
Normal file
27
vendor/cxx/tools/buck/prelude/android/exopackage.bzl
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
SECONDARY_DEX = 1
|
||||
NATIVE_LIBRARY = 2
|
||||
RESOURCES = 4
|
||||
MODULES = 8
|
||||
ARCH64 = 16
|
||||
|
||||
def get_exopackage_flags(exopackage_modes: [str.type]) -> int.type:
|
||||
flags = 0
|
||||
|
||||
for (name, flag) in [
|
||||
("secondary_dex", SECONDARY_DEX),
|
||||
("native_library", NATIVE_LIBRARY),
|
||||
("resources", RESOURCES),
|
||||
("modules", MODULES),
|
||||
("arch64", ARCH64),
|
||||
]:
|
||||
if name in exopackage_modes:
|
||||
flags += flag
|
||||
|
||||
return flags
|
||||
57
vendor/cxx/tools/buck/prelude/android/gen_aidl.bzl
vendored
Normal file
57
vendor/cxx/tools/buck/prelude/android/gen_aidl.bzl
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load(":android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
|
||||
_AidlSourceInfo = provider(fields = [
|
||||
"srcs",
|
||||
])
|
||||
|
||||
def gen_aidl_impl(ctx: "context") -> ["provider"]:
|
||||
android_toolchain = ctx.attrs._android_toolchain[AndroidToolchainInfo]
|
||||
aidl_cmd = cmd_args(android_toolchain.aidl)
|
||||
aidl_cmd.add("-p", android_toolchain.framework_aidl_file)
|
||||
aidl_cmd.add("-I", ctx.attrs.import_path)
|
||||
for path in ctx.attrs.import_paths:
|
||||
aidl_cmd.add("-I", path)
|
||||
|
||||
# We need the `aidl_srcs` files - otherwise the search on the `import_path` won't find anything.
|
||||
aidl_cmd.hidden(ctx.attrs.aidl_srcs)
|
||||
|
||||
# Allow gen_aidl rules to depend on other gen_aidl rules, and make the source files from the
|
||||
# deps accessible in this context. This is an alternative to adding dependent files in
|
||||
# aidl_srcs.
|
||||
dep_srcs = []
|
||||
for dep in ctx.attrs.deps:
|
||||
source_info = dep.get(_AidlSourceInfo)
|
||||
if source_info != None:
|
||||
dep_srcs += source_info.srcs
|
||||
else:
|
||||
warning("`{}` dependency `{}` is not a `gen_aidl` rule and will be ignored".format(ctx.label, dep.label))
|
||||
|
||||
aidl_cmd.hidden(dep_srcs)
|
||||
|
||||
aidl_out = ctx.actions.declare_output("aidl_output")
|
||||
aidl_cmd.add("-o", aidl_out.as_output())
|
||||
aidl_cmd.add(ctx.attrs.aidl)
|
||||
ctx.actions.run(aidl_cmd, category = "aidl")
|
||||
|
||||
# Put the generated Java files into a zip file to be used as srcs to other rules.
|
||||
java_toolchain = ctx.attrs._java_toolchain[JavaToolchainInfo]
|
||||
jar_cmd = cmd_args(java_toolchain.jar)
|
||||
jar_cmd.add("-cfM")
|
||||
out = ctx.actions.declare_output("{}_aidl_java_output.src.zip".format(ctx.attrs.name))
|
||||
jar_cmd.add(out.as_output())
|
||||
jar_cmd.add(aidl_out)
|
||||
|
||||
ctx.actions.run(jar_cmd, category = "aidl_jar")
|
||||
|
||||
return [
|
||||
DefaultInfo(default_outputs = [out]),
|
||||
_AidlSourceInfo(srcs = [ctx.attrs.aidl] + ctx.attrs.aidl_srcs + dep_srcs),
|
||||
]
|
||||
15
vendor/cxx/tools/buck/prelude/android/min_sdk_version.bzl
vendored
Normal file
15
vendor/cxx/tools/buck/prelude/android/min_sdk_version.bzl
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
_MIN_SDK_VERSION = 19
|
||||
_MAX_SDK_VERSION = 33
|
||||
|
||||
def get_min_sdk_version_constraint_value_name(min_sdk: int.type) -> str.type:
|
||||
return "min_sdk_version_{}".format(min_sdk)
|
||||
|
||||
def get_min_sdk_version_range() -> range.type:
|
||||
return range(_MIN_SDK_VERSION, _MAX_SDK_VERSION)
|
||||
38
vendor/cxx/tools/buck/prelude/android/prebuilt_native_library.bzl
vendored
Normal file
38
vendor/cxx/tools/buck/prelude/android/prebuilt_native_library.bzl
vendored
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load(
|
||||
"@prelude//android:android_providers.bzl",
|
||||
"PrebuiltNativeLibraryDir",
|
||||
"merge_android_packageable_info",
|
||||
)
|
||||
|
||||
def prebuilt_native_library_impl(ctx: "context") -> ["provider"]:
|
||||
if ctx.attrs.is_asset and ctx.attrs.has_wrap_script:
|
||||
fail("Cannot use `is_asset` and `has_wrap_script` in the same rule")
|
||||
|
||||
prebuilt_native_library_dir = PrebuiltNativeLibraryDir(
|
||||
raw_target = ctx.label.raw_target(),
|
||||
dir = ctx.attrs.native_libs,
|
||||
for_primary_apk = ctx.attrs.has_wrap_script,
|
||||
is_asset = ctx.attrs.is_asset,
|
||||
)
|
||||
android_packageable_info = merge_android_packageable_info(
|
||||
ctx.label,
|
||||
ctx.actions,
|
||||
ctx.attrs.deps,
|
||||
prebuilt_native_library_dir = prebuilt_native_library_dir,
|
||||
)
|
||||
return [
|
||||
# Buck1 copies the input directory and returns it as the output path. We don't
|
||||
# copy; we could just return the input directory itself as the output path, but
|
||||
# we're avoiding that (due to potential confusion from the output path being an
|
||||
# input directory) until we have an actual need for prebuilt_native_library
|
||||
# having an output path.
|
||||
DefaultInfo(),
|
||||
android_packageable_info,
|
||||
]
|
||||
55
vendor/cxx/tools/buck/prelude/android/preprocess_java_classes.bzl
vendored
Normal file
55
vendor/cxx/tools/buck/prelude/android/preprocess_java_classes.bzl
vendored
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
def get_preprocessed_java_classes(ctx: "context", input_jars = {"artifact": "target_label"}) -> {"artifact": "target_label"}:
|
||||
sh_script, _ = ctx.actions.write(
|
||||
"preprocessed_java_classes/script.sh",
|
||||
cmd_args(ctx.attrs.preprocess_java_classes_bash),
|
||||
is_executable = True,
|
||||
allow_args = True,
|
||||
)
|
||||
|
||||
preprocess_cmd = cmd_args(["/bin/bash", sh_script])
|
||||
preprocess_cmd.hidden(cmd_args(ctx.attrs.preprocess_java_classes_bash))
|
||||
for dep in ctx.attrs.preprocess_java_classes_deps:
|
||||
preprocess_cmd.hidden(dep[DefaultInfo].default_outputs + dep[DefaultInfo].other_outputs)
|
||||
|
||||
input_srcs = {}
|
||||
output_jars = {}
|
||||
|
||||
for i, (input_jar, target_label) in enumerate(input_jars.items()):
|
||||
expect(input_jar.extension == ".jar", "Expected {} to have extension .jar!".format(input_jar))
|
||||
jar_name = "{}_{}".format(i, input_jar.basename)
|
||||
input_srcs[jar_name] = input_jar
|
||||
output_jar = ctx.actions.declare_output(
|
||||
"preprocessed_java_classes/output_dir/{}".format(jar_name),
|
||||
)
|
||||
output_jars[output_jar] = target_label
|
||||
preprocess_cmd.hidden(output_jar.as_output())
|
||||
|
||||
if not output_jars:
|
||||
return {}
|
||||
|
||||
input_dir = ctx.actions.symlinked_dir("preprocessed_java_classes/input_dir", input_srcs)
|
||||
output_dir = cmd_args(output_jars.keys()[0].as_output()).parent()
|
||||
|
||||
env = {
|
||||
"ANDROID_BOOTCLASSPATH": cmd_args(
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath,
|
||||
delimiter = get_path_separator(),
|
||||
),
|
||||
"IN_JARS_DIR": cmd_args(input_dir),
|
||||
"OUT_JARS_DIR": output_dir,
|
||||
}
|
||||
|
||||
ctx.actions.run(preprocess_cmd, env = env, category = "preprocess_java_classes")
|
||||
|
||||
return output_jars
|
||||
168
vendor/cxx/tools/buck/prelude/android/proguard.bzl
vendored
Normal file
168
vendor/cxx/tools/buck/prelude/android/proguard.bzl
vendored
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//java/utils:java_utils.bzl", "get_path_separator")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
|
||||
_UNSCRUBBED_JARS_DIR = "unscrubbed"
|
||||
|
||||
ProguardOutput = record(
|
||||
jars_to_owners = {"artifact": "target_label"},
|
||||
proguard_configuration_output_file = ["artifact", None],
|
||||
proguard_mapping_output_file = "artifact",
|
||||
proguard_artifacts = ["artifact"],
|
||||
)
|
||||
|
||||
def _get_proguard_command_line_args(
|
||||
ctx: "context",
|
||||
inputs_to_unscrubbed_outputs: {"artifact": "artifact"},
|
||||
proguard_configs: ["artifact"],
|
||||
mapping: "artifact",
|
||||
configuration: ["artifact", None],
|
||||
seeds: ["artifact", None],
|
||||
usage: ["artifact", None],
|
||||
android_toolchain: "AndroidToolchainInfo") -> "cmd_args":
|
||||
cmd = cmd_args()
|
||||
cmd.add("-basedirectory", "<user.dir>")
|
||||
|
||||
android_sdk_proguard_config = ctx.attrs.android_sdk_proguard_config or "none"
|
||||
if android_sdk_proguard_config == "optimized":
|
||||
cmd.add("-include", android_toolchain.optimized_proguard_config)
|
||||
cmd.add("-optimizationpasses", str(ctx.attrs.optimization_passes))
|
||||
elif android_sdk_proguard_config == "default":
|
||||
cmd.add("-include", android_toolchain.proguard_config)
|
||||
else:
|
||||
expect(android_sdk_proguard_config == "none")
|
||||
|
||||
for proguard_config in dedupe(proguard_configs):
|
||||
cmd.add("-include")
|
||||
cmd.add(cmd_args("\"", proguard_config, "\"", delimiter = ""))
|
||||
|
||||
for jar_input, jar_output in inputs_to_unscrubbed_outputs.items():
|
||||
cmd.add("-injar", jar_input, "-outjar", jar_output if jar_output == jar_input else jar_output.as_output())
|
||||
|
||||
cmd.add("-library")
|
||||
cmd.add(cmd_args(android_toolchain.android_bootclasspath, delimiter = get_path_separator()))
|
||||
|
||||
cmd.add("-printmapping", mapping.as_output())
|
||||
if configuration:
|
||||
cmd.add("-printconfiguration", configuration.as_output())
|
||||
if seeds:
|
||||
cmd.add("-printseeds", seeds.as_output())
|
||||
if usage:
|
||||
cmd.add("-printusage", usage.as_output())
|
||||
|
||||
return cmd
|
||||
|
||||
def run_proguard(
|
||||
ctx: "context",
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
command_line_args_file: "artifact",
|
||||
command_line_args: "cmd_args",
|
||||
mapping_file: "artifact"):
|
||||
run_proguard_cmd = cmd_args()
|
||||
run_proguard_cmd.add(
|
||||
java_toolchain.java[RunInfo],
|
||||
"-XX:-MaxFDLimit",
|
||||
ctx.attrs.proguard_jvm_args,
|
||||
"-Xmx{}".format(android_toolchain.proguard_max_heap_size),
|
||||
"-jar",
|
||||
android_toolchain.proguard_jar,
|
||||
)
|
||||
run_proguard_cmd.add(cmd_args(command_line_args_file, format = "@{}"))
|
||||
run_proguard_cmd.hidden(command_line_args)
|
||||
|
||||
# Some proguard configs can propagate the "-dontobfuscate" flag which disables
|
||||
# obfuscation and prevents the mapping.txt file from being generated.
|
||||
sh_cmd = cmd_args([
|
||||
"sh",
|
||||
"-c",
|
||||
"touch $1 && $2",
|
||||
"--",
|
||||
mapping_file.as_output(),
|
||||
cmd_args(run_proguard_cmd, delimiter = " "),
|
||||
])
|
||||
|
||||
ctx.actions.run(sh_cmd, category = "run_proguard")
|
||||
|
||||
# Note that ctx.attrs.skip_proguard means that we should create the proguard command line (since
|
||||
# e.g. Redex might want to consume it) but we don't actually run the proguard command.
|
||||
def get_proguard_output(
|
||||
ctx: "context",
|
||||
input_jars: {"artifact": "target_label"},
|
||||
java_packaging_deps: ["JavaPackagingDep"],
|
||||
aapt_generated_proguard_config: ["artifact", None]) -> ProguardOutput.type:
|
||||
proguard_configs = [packaging_dep.proguard_config for packaging_dep in java_packaging_deps if packaging_dep.proguard_config]
|
||||
if ctx.attrs.proguard_config:
|
||||
proguard_configs.append(ctx.attrs.proguard_config)
|
||||
if not ctx.attrs.ignore_aapt_proguard_config and aapt_generated_proguard_config:
|
||||
proguard_configs.append(aapt_generated_proguard_config)
|
||||
|
||||
if ctx.attrs.skip_proguard:
|
||||
inputs_to_unscrubbed_outputs = {input_jar: input_jar for input_jar in input_jars.keys()}
|
||||
mapping = ctx.actions.write("proguard/mapping.txt", [])
|
||||
configuration = None
|
||||
seeds = None
|
||||
usage = None
|
||||
else:
|
||||
inputs_to_unscrubbed_outputs = {input_jar: ctx.actions.declare_output(
|
||||
"proguard_output_jars/{}/{}_{}_obfuscated.jar".format(_UNSCRUBBED_JARS_DIR, input_jar.short_path, i),
|
||||
) for i, input_jar in enumerate(input_jars.keys())}
|
||||
mapping = ctx.actions.declare_output("proguard/mapping.txt")
|
||||
configuration = ctx.actions.declare_output("proguard/configuration.txt")
|
||||
seeds = ctx.actions.declare_output("proguard/seeds.txt")
|
||||
usage = ctx.actions.declare_output("proguard/usage.txt")
|
||||
|
||||
command_line_args = _get_proguard_command_line_args(
|
||||
ctx,
|
||||
inputs_to_unscrubbed_outputs,
|
||||
proguard_configs,
|
||||
mapping,
|
||||
configuration,
|
||||
seeds,
|
||||
usage,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
)
|
||||
|
||||
command_line_args_file = ctx.actions.write("proguard/command-line.txt", command_line_args)
|
||||
|
||||
if ctx.attrs.skip_proguard:
|
||||
return ProguardOutput(
|
||||
jars_to_owners = input_jars,
|
||||
proguard_configuration_output_file = None,
|
||||
proguard_mapping_output_file = mapping,
|
||||
proguard_artifacts = [command_line_args_file, mapping],
|
||||
)
|
||||
else:
|
||||
unscrubbed_output_jars = {unscrubbed_output: input_jars[input_jar] for input_jar, unscrubbed_output in inputs_to_unscrubbed_outputs.items()}
|
||||
run_proguard(
|
||||
ctx,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo],
|
||||
command_line_args_file,
|
||||
command_line_args,
|
||||
mapping,
|
||||
)
|
||||
output_jars = {}
|
||||
for i, (unscrubbed_jar, target_label) in enumerate(unscrubbed_output_jars.items()):
|
||||
output = ctx.actions.declare_output(unscrubbed_jar.short_path.replace("{}/".format(_UNSCRUBBED_JARS_DIR), ""))
|
||||
ctx.actions.run(
|
||||
cmd_args([ctx.attrs._java_toolchain[JavaToolchainInfo].zip_scrubber, unscrubbed_jar, output.as_output()]),
|
||||
category = "scrub_jar",
|
||||
identifier = str(i),
|
||||
)
|
||||
output_jars[output] = target_label
|
||||
|
||||
return ProguardOutput(
|
||||
jars_to_owners = output_jars,
|
||||
proguard_configuration_output_file = configuration,
|
||||
proguard_mapping_output_file = mapping,
|
||||
proguard_artifacts = [command_line_args_file, mapping, configuration, seeds, usage],
|
||||
)
|
||||
229
vendor/cxx/tools/buck/prelude/android/r_dot_java.bzl
vendored
Normal file
229
vendor/cxx/tools/buck/prelude/android/r_dot_java.bzl
vendored
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//java:java_library.bzl", "compile_to_jar")
|
||||
load("@prelude//java:java_providers.bzl", "JavaClasspathEntry", "JavaLibraryInfo", "derive_compiling_deps")
|
||||
|
||||
RDotJavaSourceCode = record(
|
||||
r_dot_java_source_code_dir = "artifact",
|
||||
r_dot_java_source_code_dir_listing = "artifact",
|
||||
strings_source_code_dir = ["artifact", None],
|
||||
strings_source_code_dir_listing = ["artifact", None],
|
||||
ids_source_code_dir = ["artifact", None],
|
||||
ids_source_code_dir_listing = ["artifact", None],
|
||||
)
|
||||
|
||||
def get_dummy_r_dot_java(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
union_package: [str.type, None]) -> "JavaLibraryInfo":
|
||||
r_dot_java_source_code = _generate_r_dot_java_source_code(ctx, merge_android_resources_tool, android_resources, "dummy_r_dot_java", union_package = union_package)
|
||||
library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"dummy_r_dot_java",
|
||||
)
|
||||
return JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
)
|
||||
|
||||
def generate_r_dot_javas(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
banned_duplicate_resource_types: [str.type],
|
||||
uber_r_dot_txt_files: ["artifact"],
|
||||
override_symbols_paths: ["artifact"],
|
||||
duplicate_resources_allowlist: ["artifact", None],
|
||||
union_package: [str.type, None],
|
||||
referenced_resources_lists: ["artifact"]) -> ["JavaLibraryInfo"]:
|
||||
r_dot_java_source_code = _generate_r_dot_java_source_code(
|
||||
ctx,
|
||||
merge_android_resources_tool,
|
||||
android_resources,
|
||||
"r_dot_java",
|
||||
generate_strings_and_ids_separately = True,
|
||||
force_final_resources_ids = True,
|
||||
banned_duplicate_resource_types = banned_duplicate_resource_types,
|
||||
uber_r_dot_txt_files = uber_r_dot_txt_files,
|
||||
override_symbols_paths = override_symbols_paths,
|
||||
duplicate_resources_allowlist = duplicate_resources_allowlist,
|
||||
union_package = union_package,
|
||||
referenced_resources_lists = referenced_resources_lists,
|
||||
)
|
||||
|
||||
main_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir,
|
||||
r_dot_java_source_code.r_dot_java_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"main_r_dot_java",
|
||||
)
|
||||
strings_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.strings_source_code_dir,
|
||||
r_dot_java_source_code.strings_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"strings_r_dot_java",
|
||||
remove_classes = [".R$"],
|
||||
)
|
||||
ids_library_output = _generate_and_compile_r_dot_java(
|
||||
ctx,
|
||||
r_dot_java_source_code.ids_source_code_dir,
|
||||
r_dot_java_source_code.ids_source_code_dir_listing,
|
||||
java_toolchain,
|
||||
"ids_r_dot_java",
|
||||
remove_classes = [".R$"],
|
||||
)
|
||||
|
||||
return [JavaLibraryInfo(
|
||||
compiling_deps = derive_compiling_deps(ctx.actions, library_output, []),
|
||||
library_output = library_output,
|
||||
output_for_classpath_macro = library_output.full_library,
|
||||
) for library_output in [main_library_output, strings_library_output, ids_library_output]]
|
||||
|
||||
def _generate_r_dot_java_source_code(
|
||||
ctx: "context",
|
||||
merge_android_resources_tool: RunInfo.type,
|
||||
android_resources: ["AndroidResourceInfo"],
|
||||
identifier: str.type,
|
||||
force_final_resources_ids = False,
|
||||
generate_strings_and_ids_separately = False,
|
||||
banned_duplicate_resource_types: [str.type] = [],
|
||||
uber_r_dot_txt_files: ["artifact"] = [],
|
||||
override_symbols_paths: ["artifact"] = [],
|
||||
duplicate_resources_allowlist: ["artifact", None] = None,
|
||||
union_package: [str.type, None] = None,
|
||||
referenced_resources_lists: ["artifact"] = []) -> RDotJavaSourceCode.type:
|
||||
merge_resources_cmd = cmd_args(merge_android_resources_tool)
|
||||
|
||||
r_dot_txt_info = cmd_args()
|
||||
for android_resource in android_resources:
|
||||
r_dot_txt_info.add(cmd_args([android_resource.text_symbols, android_resource.r_dot_java_package, "_"], delimiter = " ")) # pass target name
|
||||
|
||||
r_dot_txt_info_file = ctx.actions.write("r_dot_txt_info_file_for_{}.txt".format(identifier), r_dot_txt_info)
|
||||
merge_resources_cmd.add(["--symbol-file-info", r_dot_txt_info_file])
|
||||
merge_resources_cmd.hidden([android_resource.r_dot_java_package for android_resource in android_resources])
|
||||
merge_resources_cmd.hidden([android_resource.text_symbols for android_resource in android_resources])
|
||||
|
||||
output_dir = ctx.actions.declare_output("{}_source_code".format(identifier))
|
||||
merge_resources_cmd.add(["--output-dir", output_dir.as_output()])
|
||||
output_dir_listing = ctx.actions.declare_output("{}_source_code_listing".format(identifier))
|
||||
merge_resources_cmd.add(["--output-dir-listing", output_dir_listing.as_output()])
|
||||
|
||||
if generate_strings_and_ids_separately:
|
||||
strings_output_dir = ctx.actions.declare_output("strings_source_code")
|
||||
merge_resources_cmd.add(["--strings-output-dir", strings_output_dir.as_output()])
|
||||
strings_output_dir_listing = ctx.actions.declare_output("strings_source_code_listing")
|
||||
merge_resources_cmd.add(["--strings-output-dir-listing", strings_output_dir_listing.as_output()])
|
||||
ids_output_dir = ctx.actions.declare_output("ids_source_code")
|
||||
merge_resources_cmd.add(["--ids-output-dir", ids_output_dir.as_output()])
|
||||
ids_output_dir_listing = ctx.actions.declare_output("ids_source_code_listing")
|
||||
merge_resources_cmd.add(["--ids-output-dir-listing", ids_output_dir_listing.as_output()])
|
||||
else:
|
||||
strings_output_dir = None
|
||||
strings_output_dir_listing = None
|
||||
ids_output_dir = None
|
||||
ids_output_dir_listing = None
|
||||
|
||||
if force_final_resources_ids:
|
||||
merge_resources_cmd.add("--force-final-resource-ids")
|
||||
|
||||
if len(banned_duplicate_resource_types) > 0:
|
||||
banned_duplicate_resource_types_file = ctx.actions.write("banned_duplicate_resource_types_file", banned_duplicate_resource_types)
|
||||
merge_resources_cmd.add(["--banned-duplicate-resource-types", banned_duplicate_resource_types_file])
|
||||
|
||||
if len(uber_r_dot_txt_files) > 0:
|
||||
uber_r_dot_txt_files_list = ctx.actions.write("uber_r_dot_txt_files_list", uber_r_dot_txt_files)
|
||||
merge_resources_cmd.add(["--uber-r-dot-txt", uber_r_dot_txt_files_list])
|
||||
merge_resources_cmd.hidden(uber_r_dot_txt_files)
|
||||
|
||||
if len(override_symbols_paths) > 0:
|
||||
override_symbols_paths_list = ctx.actions.write("override_symbols_paths_list", override_symbols_paths)
|
||||
merge_resources_cmd.add(["--override-symbols", override_symbols_paths_list])
|
||||
merge_resources_cmd.hidden(override_symbols_paths)
|
||||
|
||||
if duplicate_resources_allowlist != None:
|
||||
merge_resources_cmd.add(["--duplicate-resource-allowlist-path", duplicate_resources_allowlist])
|
||||
|
||||
if union_package != None:
|
||||
merge_resources_cmd.add(["--union-package", union_package])
|
||||
|
||||
if referenced_resources_lists:
|
||||
referenced_resources_file = ctx.actions.write("referenced_resources_lists", referenced_resources_lists)
|
||||
merge_resources_cmd.add(["--referenced-resources-lists", referenced_resources_file])
|
||||
merge_resources_cmd.hidden(referenced_resources_lists)
|
||||
|
||||
ctx.actions.run(merge_resources_cmd, category = "r_dot_java_merge_resources", identifier = identifier)
|
||||
|
||||
return RDotJavaSourceCode(
|
||||
r_dot_java_source_code_dir = output_dir,
|
||||
r_dot_java_source_code_dir_listing = output_dir_listing,
|
||||
strings_source_code_dir = strings_output_dir,
|
||||
strings_source_code_dir_listing = strings_output_dir_listing,
|
||||
ids_source_code_dir = ids_output_dir,
|
||||
ids_source_code_dir_listing = ids_output_dir_listing,
|
||||
)
|
||||
|
||||
def _generate_and_compile_r_dot_java(
|
||||
ctx: "context",
|
||||
r_dot_java_source_code_dir: "artifact",
|
||||
r_dot_java_src_listing: "artifact",
|
||||
java_toolchain: "JavaToolchainInfo",
|
||||
identifier: str.type,
|
||||
remove_classes: [str.type] = []) -> JavaClasspathEntry.type:
|
||||
r_dot_java_out = ctx.actions.declare_output("{}.jar".format(identifier))
|
||||
|
||||
# @lint-ignore-every BUILDIFIERLINT
|
||||
def compile_r_dot_java_srcs(ctx, artifacts, outputs):
|
||||
src_listing_string = artifacts[r_dot_java_src_listing].read_string()
|
||||
src_listing = src_listing_string.split("\n")[:-1] if src_listing_string else []
|
||||
r_dot_java_srcs = []
|
||||
copied_root = ctx.actions.declare_output("copied_{}".format(identifier))
|
||||
for path in src_listing:
|
||||
r_dot_java_srcs.append(copied_root.project(path))
|
||||
|
||||
cmd = cmd_args([
|
||||
java_toolchain.src_dir_helper[RunInfo],
|
||||
"copy",
|
||||
"--src-dir",
|
||||
r_dot_java_source_code_dir,
|
||||
"--dest-dir",
|
||||
copied_root.as_output(),
|
||||
] + src_listing)
|
||||
ctx.actions.run(
|
||||
cmd,
|
||||
category = "copy_r_dot_java_sources",
|
||||
identifier = identifier,
|
||||
)
|
||||
|
||||
compile_to_jar(
|
||||
ctx,
|
||||
output = outputs[r_dot_java_out],
|
||||
actions_prefix = identifier,
|
||||
javac_tool = None,
|
||||
srcs = r_dot_java_srcs,
|
||||
remove_classes = remove_classes,
|
||||
)
|
||||
|
||||
# Extracting an abi is unnecessary as there's not really anything to strip.
|
||||
outputs = JavaClasspathEntry(
|
||||
full_library = r_dot_java_out,
|
||||
abi = r_dot_java_out,
|
||||
required_for_source_only_abi = False,
|
||||
)
|
||||
|
||||
todo_inputs = []
|
||||
ctx.actions.dynamic_output(dynamic = [r_dot_java_src_listing], inputs = todo_inputs, outputs = [r_dot_java_out], f = compile_r_dot_java_srcs)
|
||||
return outputs
|
||||
91
vendor/cxx/tools/buck/prelude/android/robolectric_test.bzl
vendored
Normal file
91
vendor/cxx/tools/buck/prelude/android/robolectric_test.bzl
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_binary_resources_rules.bzl", "get_android_binary_resources_info")
|
||||
load("@prelude//android:android_library.bzl", "build_android_library")
|
||||
load("@prelude//android:android_providers.bzl", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_test.bzl", "build_junit_test")
|
||||
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
|
||||
load("@prelude//utils:utils.bzl", "expect")
|
||||
load("@prelude//test/inject_test_run_info.bzl", "inject_test_run_info")
|
||||
|
||||
def robolectric_test_impl(ctx: "context") -> ["provider"]:
|
||||
_verify_attributes(ctx)
|
||||
|
||||
extra_cmds = []
|
||||
|
||||
# Force robolectric to only use local dependency resolution.
|
||||
extra_cmds.append("-Drobolectric.offline=true")
|
||||
if ctx.attrs.robolectric_runtime_dependency:
|
||||
runtime_dependencies_dir = ctx.attrs.robolectric_runtime_dependency
|
||||
else:
|
||||
runtime_dependencies_dir = ctx.actions.symlinked_dir("runtime_dependencies", {
|
||||
runtime_dep.basename: runtime_dep
|
||||
for runtime_dep in ctx.attrs.robolectric_runtime_dependencies
|
||||
})
|
||||
|
||||
extra_cmds.append(cmd_args(runtime_dependencies_dir, format = "-Drobolectric.dependency.dir={}"))
|
||||
|
||||
all_packaging_deps = ctx.attrs.deps + (ctx.attrs.deps_query or []) + ctx.attrs.exported_deps + ctx.attrs.runtime_deps
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_packaging_deps)
|
||||
resources_info = get_android_binary_resources_info(
|
||||
ctx,
|
||||
all_packaging_deps,
|
||||
android_packageable_info,
|
||||
java_packaging_deps = [], # Only used for third-party jar resources, which we don't care about here.
|
||||
use_proto_format = False,
|
||||
referenced_resources_lists = [],
|
||||
)
|
||||
|
||||
test_config_properties_file = ctx.actions.write(
|
||||
"test_config.properties",
|
||||
[
|
||||
cmd_args(["android_resource_apk", resources_info.primary_resources_apk], delimiter = "="),
|
||||
cmd_args(["android_merged_manifest", resources_info.manifest], delimiter = "="),
|
||||
],
|
||||
)
|
||||
|
||||
# Robolectric looks for a file named /com/android/tools/test_config.properties on the classpath
|
||||
test_config_symlinked_dir = ctx.actions.symlinked_dir("test_config_symlinked_dir", {"com/android/tools/test_config.properties": test_config_properties_file})
|
||||
test_config_properties_jar = ctx.actions.declare_output("test_config_properties.jar")
|
||||
jar_cmd = cmd_args([
|
||||
ctx.attrs._java_toolchain[JavaToolchainInfo].jar,
|
||||
"-cfM", # -c: create new archive, -f: specify the file name, -M: do not create a manifest
|
||||
test_config_properties_jar.as_output(),
|
||||
"-C",
|
||||
test_config_symlinked_dir,
|
||||
".",
|
||||
])
|
||||
ctx.actions.run(jar_cmd, category = "test_config_properties_jar_cmd")
|
||||
extra_cmds.append(cmd_args().hidden(resources_info.primary_resources_apk, resources_info.manifest))
|
||||
|
||||
extra_classpath_entries = [test_config_properties_jar] + ctx.attrs._android_toolchain[AndroidToolchainInfo].android_bootclasspath
|
||||
extra_classpath_entries.extend([r_dot_java.library_output.full_library for r_dot_java in resources_info.r_dot_javas if r_dot_java.library_output])
|
||||
|
||||
java_providers, _ = build_android_library(ctx)
|
||||
|
||||
external_runner_test_info = build_junit_test(
|
||||
ctx,
|
||||
java_providers.java_library_info,
|
||||
java_providers.java_packaging_info,
|
||||
extra_cmds = extra_cmds,
|
||||
extra_classpath_entries = extra_classpath_entries,
|
||||
)
|
||||
|
||||
return inject_test_run_info(ctx, external_runner_test_info) + [
|
||||
java_providers.java_library_info,
|
||||
java_providers.java_packaging_info,
|
||||
java_providers.template_placeholder_info,
|
||||
java_providers.default_info,
|
||||
]
|
||||
|
||||
def _verify_attributes(ctx: "context"):
|
||||
expect(
|
||||
bool(ctx.attrs.robolectric_runtime_dependencies) != (ctx.attrs.robolectric_runtime_dependency != None),
|
||||
"Exactly one of robolectric_runtime_dependencies and robolectric_runtime_dependency must be specified!",
|
||||
)
|
||||
240
vendor/cxx/tools/buck/prelude/android/voltron.bzl
vendored
Normal file
240
vendor/cxx/tools/buck/prelude/android/voltron.bzl
vendored
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
#
|
||||
# This source code is licensed under both the MIT license found in the
|
||||
# LICENSE-MIT file in the root directory of this source tree and the Apache
|
||||
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||
# of this source tree.
|
||||
|
||||
load("@prelude//android:android_providers.bzl", "AndroidPackageableInfo", "merge_android_packageable_info")
|
||||
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
|
||||
load("@prelude//java:java_providers.bzl", "get_all_java_packaging_deps")
|
||||
load("@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", "traverse_shared_library_info")
|
||||
load("@prelude//utils:utils.bzl", "expect", "flatten")
|
||||
|
||||
# "Voltron" gives us the ability to split our Android APKs into different "modules". These
|
||||
# modules can then be downloaded on demand rather than shipped with the "main" APK.
|
||||
#
|
||||
# The module corresponding to the "main" APK is called the "root" module.
|
||||
#
|
||||
# Voltron support comes in two main parts:
|
||||
# (1) Constructing the Voltron module graph (assigning targets to each module). This is done
|
||||
# by constructing a "target graph" and then delegating to buck1 to produce the module graph.
|
||||
# (2) Using the Voltron module graph while building our APK.
|
||||
#
|
||||
# For (1), in order to calculate which targets belong to each module, we reconstruct a "target
|
||||
# graph" from "deps" information that is propagated up through AndroidPackageableInfo.
|
||||
# In buck1 we use the underlying "TargetGraph" object that is based on the raw target
|
||||
# definitions. This results in some slightly different behavior for `provided_deps` - in
|
||||
# buck2, we (correctly) ignore `provided_deps`, since they do not influence the packaging of
|
||||
# the APK, whereas in `buck1`, we treat `provided_deps` the same as `deps`.
|
||||
# In practice, this rarely affects the module assignments, but can mean that `buck2` will
|
||||
# put a target inside a module whereas `buck1` will put it into the main APK (since `buck1`
|
||||
# can find a path from an "always in main APK seed" to the target via some `provided_dep`,
|
||||
# whereas `buck2` does not).
|
||||
#
|
||||
# For (2), we package up secondary DEX files and native libs into `assets/module_name` (see
|
||||
# dex_rules.bzl and android_binary_native_rules.bzl for more information on how we do that).
|
||||
# It is worth noting that we still put all of the non-root modules into the final APK. If
|
||||
# the module should be downloaded on demand, then it is removed from the final APK in a
|
||||
# subsequent post-processing step.
|
||||
#
|
||||
# There is also an `android_app_modularity` rule that just prints out details of the Voltron
|
||||
# module graph and is used for any subsequent verification.
|
||||
def android_app_modularity_impl(ctx: "context") -> ["provider"]:
|
||||
all_deps = ctx.attrs.deps + flatten(ctx.attrs.application_module_configs.values())
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_deps)
|
||||
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in all_deps]),
|
||||
)
|
||||
traversed_shared_library_info = traverse_shared_library_info(shared_library_info)
|
||||
|
||||
cmd, output = _get_base_cmd_and_output(
|
||||
ctx.actions,
|
||||
ctx.label,
|
||||
android_packageable_info,
|
||||
traversed_shared_library_info,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs.application_module_configs,
|
||||
ctx.attrs.application_module_dependencies,
|
||||
ctx.attrs.application_module_blacklist,
|
||||
)
|
||||
|
||||
if ctx.attrs.should_include_classes:
|
||||
no_dx_target_labels = [no_dx_target.label.raw_target() for no_dx_target in ctx.attrs.no_dx]
|
||||
java_packaging_deps = [packaging_dep for packaging_dep in get_all_java_packaging_deps(ctx, all_deps) if packaging_dep.dex and packaging_dep.dex.dex.owner.raw_target() not in no_dx_target_labels]
|
||||
targets_to_jars_args = [cmd_args([str(packaging_dep.label.raw_target()), packaging_dep.jar], delimiter = " ") for packaging_dep in java_packaging_deps]
|
||||
targets_to_jars = ctx.actions.write("targets_to_jars.txt", targets_to_jars_args)
|
||||
cmd.add([
|
||||
"--targets-to-jars",
|
||||
targets_to_jars,
|
||||
]).hidden(targets_to_jars_args)
|
||||
|
||||
if ctx.attrs.should_include_libraries:
|
||||
targets_to_so_names_args = [cmd_args([str(shared_lib.label.raw_target()), so_name, str(shared_lib.can_be_asset)], delimiter = " ") for so_name, shared_lib in traversed_shared_library_info.items()]
|
||||
targets_to_so_names = ctx.actions.write("targets_to_so_names.txt", targets_to_so_names_args)
|
||||
cmd.add([
|
||||
"--targets-to-so-names",
|
||||
targets_to_so_names,
|
||||
]).hidden(targets_to_so_names_args)
|
||||
|
||||
ctx.actions.run(cmd, category = "apk_module_graph")
|
||||
|
||||
return [DefaultInfo(default_outputs = [output])]
|
||||
|
||||
def get_target_to_module_mapping(ctx: "context", deps: ["dependency"]) -> ["artifact", None]:
|
||||
if not ctx.attrs.application_module_configs:
|
||||
return None
|
||||
|
||||
all_deps = deps + flatten(ctx.attrs.application_module_configs.values())
|
||||
android_packageable_info = merge_android_packageable_info(ctx.label, ctx.actions, all_deps)
|
||||
|
||||
shared_library_info = merge_shared_libraries(
|
||||
ctx.actions,
|
||||
deps = filter(None, [x.get(SharedLibraryInfo) for x in all_deps]),
|
||||
)
|
||||
traversed_shared_library_info = traverse_shared_library_info(shared_library_info)
|
||||
|
||||
cmd, output = _get_base_cmd_and_output(
|
||||
ctx.actions,
|
||||
ctx.label,
|
||||
android_packageable_info,
|
||||
traversed_shared_library_info,
|
||||
ctx.attrs._android_toolchain[AndroidToolchainInfo],
|
||||
ctx.attrs.application_module_configs,
|
||||
ctx.attrs.application_module_dependencies,
|
||||
ctx.attrs.application_module_blacklist,
|
||||
)
|
||||
|
||||
cmd.add("--output-module-info-and-target-to-module-only")
|
||||
|
||||
ctx.actions.run(cmd, category = "apk_module_graph")
|
||||
|
||||
return output
|
||||
|
||||
def _get_base_cmd_and_output(
|
||||
actions: "actions",
|
||||
label: "label",
|
||||
android_packageable_info: "AndroidPackageableInfo",
|
||||
traversed_shared_library_info: {str.type: "SharedLibrary"},
|
||||
android_toolchain: "AndroidToolchainInfo",
|
||||
application_module_configs: {str.type: ["dependency"]},
|
||||
application_module_dependencies: [{str.type: [str.type]}, None],
|
||||
application_module_blocklist: [[["dependency"]], None]) -> ("cmd_args", "artifact"):
|
||||
deps_infos = list(android_packageable_info.deps.traverse()) if android_packageable_info.deps else []
|
||||
deps_map = {deps_info.name: deps_info.deps for deps_info in deps_infos}
|
||||
|
||||
target_graph_file = actions.write_json("target_graph.json", deps_map)
|
||||
application_module_configs_map = {
|
||||
module_name: [seed.label.raw_target() for seed in seeds if seed.get(AndroidPackageableInfo)]
|
||||
for module_name, seeds in application_module_configs.items()
|
||||
}
|
||||
application_module_configs_file = actions.write_json("application_module_configs.json", application_module_configs_map)
|
||||
application_module_dependencies_file = actions.write_json("application_module_dependencies.json", application_module_dependencies or {})
|
||||
output = actions.declare_output("apk_module_metadata.txt")
|
||||
|
||||
cmd = cmd_args([
|
||||
android_toolchain.apk_module_graph[RunInfo],
|
||||
"--root-target",
|
||||
str(label.raw_target()),
|
||||
"--target-graph",
|
||||
target_graph_file,
|
||||
"--seed-config-map",
|
||||
application_module_configs_file,
|
||||
"--app-module-dependencies-map",
|
||||
application_module_dependencies_file,
|
||||
"--output",
|
||||
output.as_output(),
|
||||
])
|
||||
|
||||
# Anything that is used by a wrap script needs to go into the primary APK, as do all
|
||||
# of their deps.
|
||||
|
||||
used_by_wrap_script_libs = [str(shared_lib.label.raw_target()) for shared_lib in traversed_shared_library_info.values() if shared_lib.for_primary_apk]
|
||||
prebuilt_native_library_dirs = list(android_packageable_info.prebuilt_native_library_dirs.traverse()) if android_packageable_info.prebuilt_native_library_dirs else []
|
||||
prebuilt_native_library_targets_for_primary_apk = [str(native_lib_dir.raw_target) for native_lib_dir in prebuilt_native_library_dirs if native_lib_dir.for_primary_apk]
|
||||
if application_module_blocklist or used_by_wrap_script_libs or prebuilt_native_library_targets_for_primary_apk:
|
||||
all_blocklisted_deps = used_by_wrap_script_libs + prebuilt_native_library_targets_for_primary_apk
|
||||
if application_module_blocklist:
|
||||
all_blocklisted_deps.extend([str(blocklisted_dep.label.raw_target()) for blocklisted_dep in flatten(application_module_blocklist)])
|
||||
|
||||
application_module_blocklist_file = actions.write(
|
||||
"application_module_blocklist.txt",
|
||||
all_blocklisted_deps,
|
||||
)
|
||||
cmd.add([
|
||||
"--always-in-main-apk-seeds",
|
||||
application_module_blocklist_file,
|
||||
])
|
||||
|
||||
return cmd, output
|
||||
|
||||
ROOT_MODULE = "dex"
|
||||
|
||||
def is_root_module(module: str.type) -> bool.type:
|
||||
return module == ROOT_MODULE
|
||||
|
||||
def all_targets_in_root_module(_module: str.type) -> str.type:
|
||||
return ROOT_MODULE
|
||||
|
||||
APKModuleGraphInfo = record(
|
||||
target_to_module_mapping_function = "function",
|
||||
module_to_canary_class_name_function = "function",
|
||||
module_to_module_deps_function = "function",
|
||||
)
|
||||
|
||||
def get_root_module_only_apk_module_graph_info() -> APKModuleGraphInfo.type:
|
||||
def root_module_canary_class_name(module: str.type):
|
||||
expect(is_root_module(module))
|
||||
return "secondary"
|
||||
|
||||
def root_module_deps(module: str.type):
|
||||
expect(is_root_module(module))
|
||||
return []
|
||||
|
||||
return APKModuleGraphInfo(
|
||||
target_to_module_mapping_function = all_targets_in_root_module,
|
||||
module_to_canary_class_name_function = root_module_canary_class_name,
|
||||
module_to_module_deps_function = root_module_deps,
|
||||
)
|
||||
|
||||
def get_apk_module_graph_info(
|
||||
ctx: "context",
|
||||
apk_module_graph_file: "artifact",
|
||||
artifacts) -> APKModuleGraphInfo.type:
|
||||
apk_module_graph_lines = artifacts[apk_module_graph_file].read_string().split("\n")
|
||||
module_count = int(apk_module_graph_lines[0])
|
||||
module_infos = apk_module_graph_lines[1:module_count + 1]
|
||||
target_to_module_lines = apk_module_graph_lines[module_count + 1:-1]
|
||||
expect(apk_module_graph_lines[-1] == "", "Expect last line to be an empty string!")
|
||||
|
||||
module_to_canary_class_name_map = {}
|
||||
module_to_module_deps_map = {}
|
||||
for line in module_infos:
|
||||
line_data = line.split(" ")
|
||||
module_name = line_data[0]
|
||||
canary_class_name = line_data[1]
|
||||
module_deps = [module_dep for module_dep in line_data[2:] if module_dep]
|
||||
module_to_canary_class_name_map[module_name] = canary_class_name
|
||||
module_to_module_deps_map[module_name] = module_deps
|
||||
|
||||
target_to_module_mapping = {str(ctx.label.raw_target()): ROOT_MODULE}
|
||||
for line in target_to_module_lines:
|
||||
target, module = line.split(" ")
|
||||
target_to_module_mapping[target] = module
|
||||
|
||||
def target_to_module_mapping_function(raw_target: str.type) -> str.type:
|
||||
return target_to_module_mapping.get(raw_target)
|
||||
|
||||
def module_to_canary_class_name_function(voltron_module: str.type) -> str.type:
|
||||
return module_to_canary_class_name_map.get(voltron_module)
|
||||
|
||||
def module_to_module_deps_function(voltron_module: str.type) -> list.type:
|
||||
return module_to_module_deps_map.get(voltron_module)
|
||||
|
||||
return APKModuleGraphInfo(
|
||||
target_to_module_mapping_function = target_to_module_mapping_function,
|
||||
module_to_canary_class_name_function = module_to_canary_class_name_function,
|
||||
module_to_module_deps_function = module_to_module_deps_function,
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue