Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
19 changes: 9 additions & 10 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@ jobs:
ghc-version: ${{ matrix.ghc-version }}
cabal-version: '3.14.2.0'

# Pinned, not `latest`: the `latest` tag is a rolling nightly, and
# buck2 core's builtin API drifts against whatever prelude/ snapshot
# is checked into this repo - confirmed directly, `latest` (as of
# 2026-09-16, built from the 2026-09-15 nightly) fails to even
# *load* prelude//cxx/link.bzl ("Unexpected parameter named
# `eager_materialization_enabled`"), while the 2026-09-01 dated
# release still builds and tests this repo's example/ cleanly in
# both dev and opt mode. Bump this tag deliberately, together with
# prelude/, rather than letting it silently float.
# Pinned, not `latest`: buck2 core's builtin API drifts against
# whatever prelude/ snapshot is checked into this repo (e.g. the
# previous snapshot passed `eager_materialization_enabled` to
# `ctx.actions.run`, which releases after 2026-09-01 reject, while
# this one needs releases from 2026-10-01 on). prelude/ is upstream's
# as of facebook/buck2@2484d70a6f8a (the commit this release was cut
# from) plus this repo's changes - bump this tag deliberately,
# together with prelude/, rather than letting it silently float.
- name: Install buck2
run: |
curl -fL https://github.com/facebook/buck2/releases/download/2026-09-01/buck2-x86_64-unknown-linux-gnu.zst -o /tmp/buck2.zst
curl -fL https://github.com/facebook/buck2/releases/download/2026-10-01/buck2-x86_64-unknown-linux-gnu.zst -o /tmp/buck2.zst
zstd -d /tmp/buck2.zst -o /usr/local/bin/buck2
chmod +x /usr/local/bin/buck2
buck2 --version
Expand Down
7 changes: 7 additions & 0 deletions prelude/BUCK
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
load("@prelude//:none.bzl", "none_rule")
load("@prelude//transitions:constraint_override_registry.bzl", "constraint_override_refs", "constraint_override_registry")
load("@prelude//utils:source_listing.bzl", "source_listing")
load(":native.bzl", prelude = "native")

Expand Down Expand Up @@ -60,3 +61,9 @@ none_rule(
name = "none",
visibility = ["PUBLIC"],
)

constraint_override_registry(
name = "constraint_override_registry",
refs = constraint_override_refs(),
visibility = ["PUBLIC"],
)
2 changes: 2 additions & 0 deletions prelude/android/android.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ load(":android_prebuilt_aar.bzl", "android_prebuilt_aar_impl")
load(":android_resource.bzl", "android_resource_impl")
load(":apk_genrule.bzl", "apk_genrule_impl")
load(":gen_aidl.bzl", "gen_aidl_impl")
load(":keystore.bzl", "keystore_impl")
load(":prebuilt_native_library.bzl", "prebuilt_native_library_impl")
load(":robolectric_test.bzl", "robolectric_test_impl")
load(":voltron.bzl", "android_app_modularity_impl")
Expand All @@ -36,6 +37,7 @@ implemented_rules = {
"android_resource": android_resource_impl,
"apk_genrule": apk_genrule_impl,
"gen_aidl": gen_aidl_impl,
"keystore": keystore_impl,
"prebuilt_native_library": prebuilt_native_library_impl,
"robolectric_test": robolectric_test_impl,
}
6 changes: 5 additions & 1 deletion prelude/android/android_aar.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ load("@prelude//android:cpu_filters.bzl", "CPU_FILTER_FOR_DEFAULT_PLATFORM", "CP
load("@prelude//android:util.bzl", "create_enhancement_context")
load("@prelude//java:java_providers.bzl", "create_java_packaging_dep", "get_all_java_packaging_deps", "get_all_java_packaging_deps_from_packaging_infos")
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
load("@prelude//target_stats:target_stats.bzl", "target_stats_aggregate_providers_and_subtargets")
load("@prelude//utils:argfile.bzl", "argfile")
load("@prelude//utils:utils.bzl", "flatten")

Expand Down Expand Up @@ -196,4 +197,7 @@ def android_aar_impl(ctx: AnalysisContext) -> list[Provider]:

ctx.actions.run(create_aar_cmd, category = "create_aar")

return [DefaultInfo(default_outputs = [aar], sub_targets = enhancement_ctx.get_sub_targets() | sub_targets)]
target_stats_providers, target_stats_subtargets = target_stats_aggregate_providers_and_subtargets(ctx, deps = deps)
sub_targets.update(target_stats_subtargets)

return [DefaultInfo(default_outputs = [aar], sub_targets = enhancement_ctx.get_sub_targets() | sub_targets)] + target_stats_providers
16 changes: 13 additions & 3 deletions prelude/android/android_apk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ load(
"AndroidBinaryResourcesInfo",
"DexFilesInfo",
"ExopackageInfo",
"KeystoreInfo",
)
load("@prelude//android:android_toolchain.bzl", "AndroidToolchainInfo")
load("@prelude//android:util.bzl", "package_validators_decorator")
load("@prelude//java:class_to_srcs.bzl", "merge_class_to_source_map_from_jar")
load("@prelude//java:java_providers.bzl", "KeystoreInfo")
load("@prelude//java:java_toolchain.bzl", "JavaToolchainInfo")
load("@prelude//java/utils:java_more_utils.bzl", "get_path_separator_for_exec_os")
load("@prelude//java/utils:java_utils.bzl", "get_class_to_source_map_info")
load("@prelude//target_stats:target_stats.bzl", "target_stats_aggregate_providers_and_subtargets")
load("@prelude//utils:argfile.bzl", "argfile")
load("@prelude//utils:utils.bzl", "flatten")

Expand Down Expand Up @@ -107,6 +108,13 @@ def android_apk_impl(ctx: AnalysisContext) -> list[Provider]:
)
]

# ctx.attrs.deps is split-transitioned here (one Dependency per ABI).
target_stats_providers, target_stats_subtargets = target_stats_aggregate_providers_and_subtargets(
ctx,
deps = android_binary_info.deps_by_platform[android_binary_info.primary_platform],
)
sub_targets.update(target_stats_subtargets)

providers = [
AndroidApkInfo(
apk = output_apk,
Expand Down Expand Up @@ -156,7 +164,10 @@ def android_apk_impl(ctx: AnalysisContext) -> list[Provider]:
},
),
class_to_srcs,
]
] + target_stats_providers

if android_binary_info.preprocessed_java_classes_info:
providers.append(android_binary_info.preprocessed_java_classes_info)

# Expose the exopackage secondary-dex dir so android_instrumentation_test can push it to the device.
if exopackage_info != None and exopackage_info.secondary_dex_info != None:
Expand Down Expand Up @@ -314,7 +325,6 @@ def get_install_config(apex_mode: bool) -> dict[str, typing.Any]:
"adb_restart_on_failure": read_root_config("adb", "adb_restart_on_failure", "true"),
"apex_mode": apex_mode,
"multi_install_mode": read_root_config("adb", "multi_install_mode", "false"),
"skip_install_metadata": read_root_config("adb", "skip_install_metadata", "false"),
"staged_install_mode": read_root_config("adb", "staged_install_mode", None),
}

Expand Down
100 changes: 10 additions & 90 deletions prelude/android/android_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ load(
"AndroidBinaryNativeLibsInfo", # @unused Used as type
"AndroidBinaryResourcesInfo", # @unused Used as type
"AndroidBuildConfigInfo", # @unused Used as type
"AndroidPreprocessedJavaClassesInfo", # @unused Used as type
"BuildConfigField",
"DexFilesInfo",
"merge_android_packageable_info",
Expand All @@ -27,8 +28,6 @@ load("@prelude//android:exopackage.bzl", "get_exopackage_flags")
load("@prelude//android:preprocess_java_classes.bzl", "get_preprocessed_java_classes")
load("@prelude//android:util.bzl", "create_enhancement_context")
load("@prelude//android:voltron.bzl", "get_target_to_module_mapping")
load("@prelude//java:dex.bzl", "get_dex_produced_from_java_library")
load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo")
load(
"@prelude//java:java_providers.bzl",
"JavaPackagingDep", # @unused Used as type
Expand All @@ -40,18 +39,6 @@ load(
load("@prelude//java:proguard.bzl", "get_proguard_output")
load("@prelude//utils:expect.bzl", "expect")

def _preprocessed_jars_args(jars: list[Artifact]):
return cmd_args(jars)

# Holds the preprocessed jar set in a single node so that each pre_dex action can reference one
# shared projection. Handing the raw list to every action instead retains a copy of it per action,
# which is quadratic in the number of jars.
PreprocessedJarsTSet = transitive_set(
args_projections = {
"jars": _preprocessed_jars_args,
},
)

AndroidBinaryInfo = record(
sub_targets = dict,
java_packaging_deps = list[JavaPackagingDep],
Expand All @@ -61,12 +48,14 @@ AndroidBinaryInfo = record(
native_library_info = AndroidBinaryNativeLibsInfo,
resources_info = AndroidBinaryResourcesInfo,
materialized_artifacts = list[Artifact],
preprocessed_java_classes_info = AndroidPreprocessedJavaClassesInfo | None,
validation_outputs = list[Artifact],
)

def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBinaryInfo:
sub_targets = {}
materialized_artifacts = []
preprocessed_java_classes_info = None

deps_by_platform = get_deps_by_platform(ctx)
primary_platform = CPU_FILTER_FOR_PRIMARY_PLATFORM if CPU_FILTER_FOR_PRIMARY_PLATFORM in deps_by_platform else CPU_FILTER_FOR_DEFAULT_PLATFORM
Expand All @@ -88,8 +77,6 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
)
should_pre_dex = not ctx.attrs.disable_pre_dex and not has_proguard_config and not ctx.attrs.preprocess_java_classes_bash

preprocess_predex_merge = ctx.attrs.preprocess_java_classes_bash and not has_proguard_config and not ctx.attrs.disable_pre_dex

enhancement_ctx = create_enhancement_context(ctx)
if target_to_module_mapping_file:
enhancement_ctx.debug_output("module.mapping", target_to_module_mapping_file)
Expand Down Expand Up @@ -132,7 +119,7 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
use_proto_format = use_proto_format,
referenced_resources_lists = referenced_resources_lists,
manifest_entries = ctx.attrs.manifest_entries,
generate_strings_and_ids_separately = should_pre_dex or preprocess_predex_merge,
generate_strings_and_ids_separately = should_pre_dex,
aapt2_preferred_density = ctx.attrs.aapt2_preferred_density,
)
sub_targets["manifest"] = [DefaultInfo(default_output = resources_info.manifest)]
Expand All @@ -157,7 +144,7 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
default_output = r_dot_java_info.source_zipped,
),
]
validation_outputs = []
validation_outputs = list(native_library_info.validation_outputs)
dex_java_packaging_deps = [
packaging_dep for packaging_dep in java_packaging_deps if packaging_dep.dex and packaging_dep.dex.dex.owner.raw_target() not in no_dx_target_labels
]
Expand Down Expand Up @@ -192,9 +179,9 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
)

if ctx.attrs.preprocess_java_classes_bash:
jars_to_owners, materialized_artifacts_dir = get_preprocessed_java_classes(enhancement_ctx, jars_to_owners)
if materialized_artifacts_dir:
materialized_artifacts.append(materialized_artifacts_dir)
jars_to_owners, preprocessed_java_classes_info = get_preprocessed_java_classes(enhancement_ctx, jars_to_owners)
if preprocessed_java_classes_info:
materialized_artifacts.append(preprocessed_java_classes_info.materialized_artifacts_dir)
if has_proguard_config:
additional_proguard_configs = (
[resources_info.proguard_config_file] if not ctx.attrs.ignore_aapt_proguard_config and resources_info.proguard_config_file else []
Expand Down Expand Up @@ -236,75 +223,7 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
else:
proguard_output = None

if preprocess_predex_merge:
dex_toolchain = ctx.attrs._dex_toolchain[DexToolchainInfo]
preprocessed_jars = list(jars_to_owners.keys())

# R.java jars are byte-light but field-heavy (one field per resource id) and are
# re-dexed from scratch here. Dexing them with the default weight factor packs the
# whole R.java jar into a single secondary dex, overflowing the 64K field-reference
# limit. Preserve the r_dot_java_weight_factor that compiled_r_dot_java_deps applies
# on the non-preprocessed path so R.java spreads across secondary dexes here too.
r_dot_java_jar_basenames = [dep.jar.basename for dep in compiled_r_dot_java_deps]

# Every jar desugars against the whole preprocessed set, so the classpath is identical
# for all of them. Share one projection and one classpath file rather than rebuilding
# both per jar.
desugar_deps = ctx.actions.tset(PreprocessedJarsTSet, value = preprocessed_jars).project_as_args("jars")
desugar_deps_file = ctx.actions.write(
"preprocessed_desugar_deps_file.txt",
desugar_deps,
has_content_based_path = True,
)
pre_dexed_libs = []
pre_dexed_artifacts_to_owners = {}
for jar in preprocessed_jars:
weight_factor = 1
for r_dot_java_jar_basename in r_dot_java_jar_basenames:
if jar.basename.endswith(r_dot_java_jar_basename):
weight_factor = android_toolchain.r_dot_java_weight_factor * 2
break
pre_dexed_lib = get_dex_produced_from_java_library(
ctx,
dex_toolchain = dex_toolchain,
jar_to_dex = jar,
needs_desugar = True,
desugar_deps = desugar_deps,
weight_factor = weight_factor,
desugar_deps_file = desugar_deps_file,
)
pre_dexed_libs.append(pre_dexed_lib)
if pre_dexed_lib.dex:
pre_dexed_artifacts_to_owners[pre_dexed_lib.dex] = jars_to_owners[jar]
if ctx.attrs.use_split_dex:
multidex_min_api = ctx.attrs.multidex_min_api
if multidex_min_api == None:
multidex_min_api = getattr(ctx.attrs, "_dex_min_sdk_version", None)
if multidex_min_api == None:
multidex_min_api = ctx.attrs.min_sdk_version
if multidex_min_api != None and int(multidex_min_api) > 21 and not ctx.attrs.primary_dex_patterns:
dex_files_info = get_multi_dex(
ctx,
android_toolchain,
pre_dexed_artifacts_to_owners,
ctx.attrs.primary_dex_patterns,
apk_module_graph_file = target_to_module_mapping_file,
enable_bootstrap_dexes = ctx.attrs.enable_bootstrap_dexes,
multidex_min_api = str(multidex_min_api),
pre_dexed_inputs = True,
)
else:
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,
enable_bootstrap_dexes = ctx.attrs.enable_bootstrap_dexes,
)
else:
dex_files_info = merge_to_single_dex(ctx, android_toolchain, pre_dexed_libs)
elif ctx.attrs.use_split_dex:
if ctx.attrs.use_split_dex:
dex_files_info = get_multi_dex(
ctx,
android_toolchain,
Expand Down Expand Up @@ -344,6 +263,7 @@ def get_binary_info(ctx: AnalysisContext, use_proto_format: bool) -> AndroidBina
native_library_info = native_library_info,
resources_info = resources_info,
materialized_artifacts = materialized_artifacts,
preprocessed_java_classes_info = preprocessed_java_classes_info,
validation_outputs = validation_outputs,
)

Expand Down
Loading
Loading