Skip to main content
Glama
java_providers.bzl32.9 kB
# 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//:resources.bzl", "ResourceInfo", "gather_resources", ) load("@prelude//java:class_to_srcs.bzl", "JavaClassToSourceMapInfo") load("@prelude//java:dex.bzl", "DexLibraryInfo", "get_dex_produced_from_java_library") load("@prelude//java:dex_toolchain.bzl", "DexToolchainInfo") load("@prelude//java/utils:java_more_utils.bzl", "get_path_separator_for_exec_os") load("@prelude//linking:linkable_graph.bzl", "LinkableGraph", "create_linkable_graph") load( "@prelude//linking:shared_libraries.bzl", "SharedLibraryInfo", "merge_shared_libraries", ) load("@prelude//utils:expect.bzl", "expect") load( "@prelude//utils:utils.bzl", "flatten", ) # JAVA PROVIDER DOCS # # Our core Java provider is JavaLibraryInfo. At a basic level, this provider needs to give # its dependents the ability to do two things: compilation and packaging. # # Compilation # # When we compile, we need to add all of our dependencies to the classpath. That includes # anything in `deps`, `exported_deps`, `provided_deps` and `exported_provided_deps`, (but # not `runtime_deps`). Additionally, it includes anything that these dependencies export # (via `exported_deps` or `exported_provided_deps`). For example, if A depends upon B, # and B has an exported dependency on C, then we need to add both B and C to the classpath # when compiling A, i.e. both B and C need to be part of B's `compiling_deps`. # # Therefore, the `compiling_deps` consist of the library's own output (if it exists) plus # the `compiling_deps` of any `exported_deps` and `exported_provided_deps`. # # When we compile, we don't need to compile against the full library - instead, we just # compile against the library's public interface, or ABI. # # Packaging # # When we package our Java code into a `java_binary`, we need to include all of the Java # code that is need to run the application - i.e. all the transitive dependencies. That # includes anything in `deps`, `exported_deps` and `runtime_deps` (but not `provided_deps` # or `exported_provided_deps`). For example, if A depends upon B, and B has a `dep` on C # and a `provided_dep` on D, then if we package A we also need to include B and C, but # not D. # # Therefore, the `packaging_deps` consist of the library's own output (if it exists) plus # the `packaging_deps` of any `deps`, `exported_deps` and `runtime_deps`. # # When we package, we need to use the full library (since we are actually going to be # running the code contained in the library). # # We also need to package up any native code that is declared transitively. The # `SharedLibraryInfo` also consists of the `SharedLibraryInfo` of any `deps`, # `exported_deps` and `runtime_deps`. # # Android # # Because Android uses Java, and we don't currently have the ability to "overlay" our # providers, the core Java providers are extended to support Android's requirements. # This introduces some additional complexity. # # Android doesn't package Java bytecode, but instead it converts the Java bytecode # .dex (Dalvik Executable) files that are packaged into the Android binary (either an # APK or an AAB). Therefore, our `packaging_deps` contain not just a `jar` field but # also a `dex` field. If the `dex` field is empty, then the dep should not be # packaged into the APK - this is useful for things like `android_build_config` where # we want the output (.jar) to be present in any Java annotation processors that we # run, but not in the final binary (since we rewrite the build config at the binary # level anyway). # # Android also provides the ability to run Proguard on your binary in order to # remove unused classes etc. Each Java library can specify any classes that it wants # to always keep etc, via a `proguard_config`. This config also needs to be added to # the `packaging_deps`. # # Java-like rules also provide a "special" function that can be used inside queries: # "classpath". `classpath(A)` returns all of the packaging deps of A, while # `classpath(A, 1)` returns all of the first-order packaging deps of A. JavaClasspathEntry = record( full_library = field(Artifact), abi = field(Artifact), # abi_as_dir is the abi .jar unzipped into a directory. If available, it is used to provide # .class level granularity for javacd and kotlincd dep-files. abi_as_dir = field(Artifact | None), required_for_source_only_abi = field(bool), abi_jar_snapshot = field(Artifact | None), ) def _args_for_ast_dumper(entry: JavaClasspathEntry): return [ "--dependency", '"{}"'.format(entry.abi.owner), entry.abi, ] def _args_for_compiling(entry: JavaClasspathEntry): return entry.abi def _javacd_json(v): return v.abi def _abi_to_abi_dir(entry: JavaClasspathEntry): if entry.abi_as_dir: return cmd_args([entry.abi, entry.abi_as_dir], delimiter = " ") return [] JavaCompilingDepsTSet = transitive_set( args_projections = { "abi_to_abi_dir": _abi_to_abi_dir, "args_for_ast_dumper": _args_for_ast_dumper, "args_for_compiling": _args_for_compiling, }, json_projections = { "javacd_json": _javacd_json, }, ) JavaPackagingDep = record( label = Label, jar = Artifact | None, dex = [DexLibraryInfo, None], gwt_module = Artifact | None, is_prebuilt_jar = bool, proguard_config = Artifact | None, # An output that is used solely by the system to have an artifact bound to the target (that the core can then use to find # the right target from the given artifact). output_for_classpath_macro = Artifact, sources_jar = Artifact | None, ) def _full_jar_args(dep: JavaPackagingDep): if dep.jar: return cmd_args(dep.jar) return cmd_args() def _args_for_classpath_macro(dep: JavaPackagingDep): return dep.output_for_classpath_macro def _packaging_dep_javacd_json(dep: JavaPackagingDep): return dep.jar or "" JavaPackagingDepTSet = transitive_set( args_projections = { "args_for_classpath_macro": _args_for_classpath_macro, "full_jar_args": _full_jar_args, }, json_projections = { "javacd_json": _packaging_dep_javacd_json, }, ) JavaGlobalCodeInfo = provider( doc = """This dictionary maps a framework key to its corresponding GlobalCodeConfig. The GlobalCodeConfig specifies the dependency .jars required by the framework for global-level code generation (binary level). The process responsible for generating the global_code_info provider for the target utilizes this mapping to: * Retrieve the GlobalCodeConfig associated with each framework, identified by its key. * Determine whether the .jar files for the library or any of its dependencies are necessary for global code generation for that particular framework. * Create a mapping from each framework key to a list of the required .jars identified in the previous step.""", fields = { "global_code_map": provider_field(typing.Any, default = None), # "{name: JavaCompilingDepsTSet}" }, ) JavaLibraryInfo = provider( doc = "Information about a java library and its dependencies", fields = { # Java dependencies exposed to dependent targets and supposed to be used during compilation. # Consisting of this library's own output, and the "compiling_deps" of any exported_deps and exported_provided_deps. # "compiling_deps": provider_field(typing.Any, default = None), # ["JavaCompilingDepsTSet", None] # An output of the library. If present then already included into `compiling_deps` field. "library_output": provider_field(typing.Any, default = None), # ["JavaClasspathEntry", None] # Shows if the library can be exported or not "may_not_be_exported": provider_field(typing.Any, default = None), # Shows if the library can be packaged or not "may_not_be_packaged": provider_field(typing.Any, default = None), # An output that is used solely by the system to have an artifact bound to the target (that the core can then use to find # the right target from the given artifact). "output_for_classpath_macro": provider_field(typing.Any, default = None), # "artifact" }, ) JavaLibraryIntellijInfo = provider( doc = "Information about a java library that is required for Intellij project generation", fields = { # Directory containing external annotation jars "annotation_jars_dir": provider_field(typing.Any, default = None), # ["artifact", None] # All the artifacts that were used in order to compile this library "compiling_classpath": provider_field(typing.Any, default = None), # ["artifact"] "generated_sources": provider_field(typing.Any, default = None), # ["artifact"] "lint_jar": provider_field(typing.Any, default = None), # ["artifact"] # If this library has a jar_postprocessor, this is the jar prior to post-processing. # Otherwise, it is the same as library_output in JavaLibraryInfo. "preprocessed_library": provider_field(typing.Any, default = None), # ["artifact", None] "used_jars_json": provider_field(typing.Any, default = None), # ["artifact"] }, ) JavaPackagingInfo = provider( fields = { # Presents all java dependencies used to build this library and it's dependencies (all transitive deps except provided ones). # These deps must be included into the final artifact. "packaging_deps": provider_field(typing.Any, default = None), # ["JavaPackagingDepTSet", None], }, ) KeystoreInfo = provider( # @unsorted-dict-items fields = { "store": provider_field(typing.Any, default = None), # artifact "properties": provider_field(typing.Any, default = None), # artifact }, ) JavaCompileOutputs = record( full_library = Artifact, class_abi = Artifact | None, source_abi = Artifact | None, source_only_abi = Artifact | None, classpath_entry = JavaClasspathEntry, annotation_processor_output = Artifact | None, preprocessed_library = Artifact, incremental_state_dir = Artifact | None, used_jars_json = Artifact | None, ) JavaProviders = record( java_library_info = JavaLibraryInfo, java_library_intellij_info = JavaLibraryIntellijInfo, java_packaging_info = JavaPackagingInfo, java_global_code_info = JavaGlobalCodeInfo, shared_library_info = SharedLibraryInfo, cxx_resource_info = ResourceInfo, linkable_graph = LinkableGraph, template_placeholder_info = TemplatePlaceholderInfo, default_info = DefaultInfo, class_to_src_map = [JavaClassToSourceMapInfo, None], validation_info = [ValidationInfo, None], ) def to_list(java_providers: JavaProviders) -> list[Provider]: providers = [ java_providers.java_library_info, java_providers.java_library_intellij_info, java_providers.java_packaging_info, java_providers.java_global_code_info, java_providers.shared_library_info, java_providers.cxx_resource_info, java_providers.linkable_graph, java_providers.template_placeholder_info, java_providers.default_info, ] if java_providers.class_to_src_map != None: providers.append(java_providers.class_to_src_map) if java_providers.validation_info != None: providers.append(java_providers.validation_info) return providers # Creates a JavaCompileOutputs. `classpath_abi` can be set to specify a # specific artifact to be used as the abi for the JavaClasspathEntry. def make_compile_outputs( full_library: Artifact, preprocessed_library: Artifact, class_abi: Artifact | None = None, source_abi: Artifact | None = None, source_only_abi: Artifact | None = None, classpath_abi: Artifact | None = None, classpath_abi_dir: Artifact | None = None, required_for_source_only_abi: bool = False, annotation_processor_output: Artifact | None = None, incremental_state_dir: Artifact | None = None, abi_jar_snapshot: Artifact | None = None, used_jars_json: Artifact | None = None) -> JavaCompileOutputs: expect(classpath_abi != None or classpath_abi_dir == None, "A classpath_abi_dir should only be provided if a classpath_abi is provided!") return JavaCompileOutputs( full_library = full_library, class_abi = class_abi, source_abi = source_abi, source_only_abi = source_only_abi, classpath_entry = JavaClasspathEntry( full_library = full_library, abi = classpath_abi or class_abi or full_library, abi_as_dir = classpath_abi_dir, required_for_source_only_abi = required_for_source_only_abi, abi_jar_snapshot = abi_jar_snapshot, ), annotation_processor_output = annotation_processor_output, preprocessed_library = preprocessed_library, incremental_state_dir = incremental_state_dir, used_jars_json = used_jars_json, ) def create_abi(actions: AnalysisActions, class_abi_generator: Dependency, library: Artifact, keepSynthetic: bool = False) -> Artifact: # It's possible for the library to be created in a subdir that is # itself some actions output artifact, so we replace directory # separators to get a path that we can uniquely own. # TODO(cjhopman): This probably should take in the output path. class_abi = actions.declare_output("{}-class-abi.jar".format(library.short_path.replace("/", "_"))) cmd = [ class_abi_generator[RunInfo], library, class_abi.as_output(), ] if keepSynthetic: cmd.append("--keep-synthetic") actions.run( cmd, category = "class_abi_generation", identifier = library.short_path, ) return class_abi ClasspathSnapshotGranularity = enum("CLASS_LEVEL", "CLASS_MEMBER_LEVEL") def generate_java_classpath_snapshot(actions: AnalysisActions, snapshot_generator: Dependency | None, granularity: ClasspathSnapshotGranularity, library: Artifact, action_identifier: str | None) -> Artifact | None: if not snapshot_generator: return None identifier = ( "{}_".format(action_identifier) if action_identifier else "" ) + library.short_path.replace("/", "_").split(".")[0] output = actions.declare_output("{}_jar_snapshot_{}.bin".format( identifier, "cl" if ClasspathSnapshotGranularity("CLASS_LEVEL") == granularity else "cml", )) actions.run( [ snapshot_generator[RunInfo], "--input-jar", library, "--output-snapshot", output.as_output(), "--granularity", granularity.value, ], category = "jar_snapshot", identifier = identifier, ) return output def single_library_compiling_deps( actions: AnalysisActions, library_output: [JavaClasspathEntry, None]) -> [JavaCompilingDepsTSet, None]: if library_output: return actions.tset(JavaCompilingDepsTSet, value = library_output) else: return None # Accumulate deps necessary for compilation, which consist of this library's output and compiling_deps of its exported deps def derive_compiling_deps( actions: AnalysisActions, library_output: [JavaCompilingDepsTSet, None], children: list[Dependency]) -> [JavaCompilingDepsTSet, None]: if children: filtered_children = filter( None, [exported_dep.compiling_deps for exported_dep in filter(None, [x.get(JavaLibraryInfo) for x in children])], ) children = filtered_children if not library_output and not children: return None return actions.tset(JavaCompilingDepsTSet, children = (children or []) + ([library_output] if library_output else [])) def create_java_packaging_dep( ctx: AnalysisContext, library_jar: Artifact | None = None, output_for_classpath_macro: Artifact | None = None, needs_desugar: bool = False, desugar_deps: list[Artifact] = [], is_prebuilt_jar: bool = False, has_srcs: bool = True, sources_jar: Artifact | None = None, dex_weight_factor: int = 1, proguard_config: Artifact | None = None, gwt_module: Artifact | None = None) -> JavaPackagingDep: dex_toolchain = getattr(ctx.attrs, "_dex_toolchain", None) if library_jar != None and has_srcs and dex_toolchain != None and ctx.attrs._dex_toolchain[DexToolchainInfo].d8_command != None: dex = get_dex_produced_from_java_library( ctx, ctx.attrs._dex_toolchain[DexToolchainInfo], library_jar, needs_desugar, desugar_deps, dex_weight_factor, ) else: dex = None expect(library_jar != None or output_for_classpath_macro != None, "Must provide an output_for_classpath_macro if no library_jar is provided!") return JavaPackagingDep( label = ctx.label, jar = library_jar, dex = dex, gwt_module = gwt_module, is_prebuilt_jar = is_prebuilt_jar, proguard_config = proguard_config or getattr(ctx.attrs, "proguard_config", None), output_for_classpath_macro = output_for_classpath_macro or library_jar, sources_jar = sources_jar, ) def get_all_java_packaging_deps(ctx: AnalysisContext, deps: list[Dependency]) -> list[JavaPackagingDep]: return get_all_java_packaging_deps_from_packaging_infos(ctx, filter(None, [x.get(JavaPackagingInfo) for x in deps])) def get_all_java_packaging_deps_from_packaging_infos(ctx: AnalysisContext, infos: list[JavaPackagingInfo]) -> list[JavaPackagingDep]: children = filter(None, [info.packaging_deps for info in infos]) if not children: return [] tset = ctx.actions.tset(JavaPackagingDepTSet, children = children) return list(tset.traverse()) def get_all_java_packaging_deps_tset( ctx: AnalysisContext, java_packaging_infos: list[JavaPackagingInfo], java_packaging_dep: [JavaPackagingDep, None] = None) -> [JavaPackagingDepTSet, None]: packaging_deps_kwargs = {} if java_packaging_dep: packaging_deps_kwargs["value"] = java_packaging_dep packaging_deps_children = filter(None, [info.packaging_deps for info in java_packaging_infos]) if packaging_deps_children: packaging_deps_kwargs["children"] = packaging_deps_children return ctx.actions.tset(JavaPackagingDepTSet, **packaging_deps_kwargs) if packaging_deps_kwargs else None # Accumulate deps necessary for packaging, which consist of all transitive java deps (except provided ones) def get_java_packaging_info( ctx: AnalysisContext, raw_deps: list[Dependency], java_packaging_dep: [JavaPackagingDep, None] = None) -> JavaPackagingInfo: java_packaging_infos = filter(None, [x.get(JavaPackagingInfo) for x in raw_deps]) packaging_deps = get_all_java_packaging_deps_tset(ctx, java_packaging_infos, java_packaging_dep) return JavaPackagingInfo(packaging_deps = packaging_deps) def _create_java_compiling_deps_tset_for_global_code( actions: AnalysisActions, global_code_libraries: list[JavaCompilingDepsTSet], name: str, global_code_infos: list[JavaGlobalCodeInfo]) -> [JavaCompilingDepsTSet, None]: global_code_jars_children = filter(None, [info.global_code_map.get(name, None) for info in global_code_infos]) if global_code_libraries: global_code_jars_children.extend(global_code_libraries) if not global_code_jars_children: return None elif len(global_code_jars_children) == 1: return global_code_jars_children[0] else: return actions.tset(JavaCompilingDepsTSet, children = global_code_jars_children) # This function identifies and collects necessary dependencies that meet criteria defined in `GLOBAL_CODE_CONFIG` for global code generation across frameworks. # It maps framework names to their corresponding Java compiling dependency sets. # Example: Below configuration specifies criteria for the "di" framework: # GLOBAL_CODE_CONFIG = { # "di": ( # triggers = ["//fbandroid/java/com/facebook/inject:inject"], # deps = [], # requires_first_order_classpath = False, # ), # } # With this setup, if a target depends on "//fbandroid/java/com/facebook/inject:inject", the `global_code_info` provider for that target will have an entry under "di". # This entry will be a JavaCompilingDepsTSet containing the .jar files associated with that target. # Each framework (like "di") can use a Buck rule to identify dependencies with matching values for their framework key in the `global_code_info` provider. # They can then compile all the .jars needed for global code generation. def get_global_code_info( ctx: AnalysisContext, declared_deps: list[Dependency], packaging_deps: list[Dependency], single_library_dep: [JavaCompilingDepsTSet, None], library_compiling_deps: [JavaCompilingDepsTSet, None], first_order_compiling_deps_without_library_itself: [JavaCompilingDepsTSet, None], global_code_config: dict) -> JavaGlobalCodeInfo: global_code_infos = filter(None, [x.get(JavaGlobalCodeInfo) for x in packaging_deps]) declared_deps_raw_targets = [declared_dep.label.raw_target() for declared_dep in declared_deps] def declared_deps_contains_trigger(deps_triggers: set[TargetLabel]) -> TargetLabel | None: for declared_deps_raw_target in declared_deps_raw_targets: if declared_deps_raw_target in deps_triggers: return declared_deps_raw_target return None global_code_map = {} for name, (config) in global_code_config.items(): contains_trigger = declared_deps_contains_trigger(config.triggers) target_is_global_code_dep = ctx.label.raw_target() in config.deps if (contains_trigger or target_is_global_code_dep) and config.requires_first_order_classpath: global_code_library_compiling_deps = [] if single_library_dep: global_code_library_compiling_deps.append(single_library_dep) if first_order_compiling_deps_without_library_itself: global_code_library_compiling_deps.append(first_order_compiling_deps_without_library_itself) elif target_is_global_code_dep: global_code_library_compiling_deps = [library_compiling_deps] elif contains_trigger: if single_library_dep == None: # We have to have single_library_dep - otherwise there is no output. # This /should/ be a failure - however there are WAY too many places that do not follow this pattern to effectively fail here. #fail("Target {} contains dep {} which is a 'trigger' for the global code rule {}, but the target does not produce any output. ".format( # ctx.label.raw_target(), # contains_trigger, # name, # ) + # "If the target does not export anything, it can be removed completely, or otherwise just remove all of the deps.") global_code_library_compiling_deps = [] else: global_code_library_compiling_deps = [single_library_dep] else: global_code_library_compiling_deps = [] global_code_tset = _create_java_compiling_deps_tset_for_global_code(ctx.actions, global_code_library_compiling_deps, name, global_code_infos) if global_code_tset: global_code_map[name] = global_code_tset return JavaGlobalCodeInfo(global_code_map = global_code_map) def propagate_global_code_info( ctx: AnalysisContext, packaging_deps: list[Dependency]) -> JavaGlobalCodeInfo: global_code_map = {} global_code_infos = filter(None, [x.get(JavaGlobalCodeInfo) for x in packaging_deps]) keys = set(flatten([info.global_code_map.keys() for info in global_code_infos])) for key in keys: global_code_tset = _create_java_compiling_deps_tset_for_global_code(ctx.actions, [], key, global_code_infos) if global_code_tset: global_code_map[key] = global_code_tset return JavaGlobalCodeInfo(global_code_map = global_code_map) def create_native_providers(ctx: AnalysisContext, label: Label, packaging_deps: list[Dependency]) -> (SharedLibraryInfo, ResourceInfo, LinkableGraph): shared_library_info = merge_shared_libraries( ctx.actions, deps = filter(None, [x.get(SharedLibraryInfo) for x in packaging_deps]), ) cxx_resource_info = ResourceInfo(resources = gather_resources( label, deps = packaging_deps, )) linkable_graph = create_linkable_graph(ctx, deps = filter(None, [x.get(LinkableGraph) for x in packaging_deps])) return shared_library_info, cxx_resource_info, linkable_graph def _create_non_template_providers( ctx: AnalysisContext, library_output: [JavaClasspathEntry, None], global_code_config, declared_deps: list[Dependency] = [], exported_deps: list[Dependency] = [], exported_provided_deps: list[Dependency] = [], runtime_deps: list[Dependency] = [], needs_desugar: bool = False, desugar_classpath: list[Artifact] = [], is_prebuilt_jar: bool = False, has_srcs: bool = True, sources_jar: Artifact | None = None, proguard_config: Artifact | None = None, gwt_module: Artifact | None = None, first_order_compiling_deps_without_library_itself: JavaCompilingDepsTSet | None = None, dex_weight_factor: int = 1) -> (JavaLibraryInfo, JavaPackagingInfo, JavaGlobalCodeInfo, SharedLibraryInfo, ResourceInfo, LinkableGraph): """Creates java library providers of type `JavaLibraryInfo` and `JavaPackagingInfo`. Args: library_output: optional JavaClasspathEntry that represents library output declared_deps: declared dependencies (usually comes from `deps` field of the rule) exported_deps: dependencies that are exposed to dependent rules as compiling deps exported_provided_deps: dependencies that are are exposed to dependent rules and not be included into packaging runtime_deps: dependencies that are used for packaging only """ packaging_deps = declared_deps + exported_deps + runtime_deps for dep in packaging_deps: if JavaLibraryInfo in dep and dep[JavaLibraryInfo].may_not_be_packaged: fail("{} has 'may_not_be_packaged' label but is present in {}. If you need to use it in order to build the library, move it into 'provided_deps'".format( dep.label.raw_target(), ctx.label.raw_target(), )) shared_library_info, cxx_resource_info, linkable_graph = create_native_providers(ctx, ctx.label, packaging_deps) output_for_classpath_macro = library_output.abi if (library_output and library_output.abi.owner != None) else ctx.actions.write("dummy_output_for_classpath_macro.txt", "Unused") java_packaging_dep = create_java_packaging_dep( ctx, library_output.full_library if library_output else None, output_for_classpath_macro, needs_desugar, desugar_classpath, is_prebuilt_jar, has_srcs, sources_jar, proguard_config = proguard_config, gwt_module = gwt_module, dex_weight_factor = dex_weight_factor, ) java_packaging_info = get_java_packaging_info( ctx, raw_deps = packaging_deps, java_packaging_dep = java_packaging_dep, ) single_library = single_library_compiling_deps(ctx.actions, library_output) compiling_deps = derive_compiling_deps(ctx.actions, single_library, exported_deps + exported_provided_deps) global_code_info = get_global_code_info( ctx, declared_deps, packaging_deps, single_library, compiling_deps, first_order_compiling_deps_without_library_itself, global_code_config, ) return ( JavaLibraryInfo( compiling_deps = compiling_deps, library_output = library_output, output_for_classpath_macro = output_for_classpath_macro, may_not_be_exported = "may_not_be_exported" in (ctx.attrs.labels or []), may_not_be_packaged = "may_not_be_packaged" in (ctx.attrs.labels or []), ), java_packaging_info, global_code_info, shared_library_info, cxx_resource_info, linkable_graph, ) def create_template_info(ctx: AnalysisContext, packaging_info: JavaPackagingInfo, first_order_classpath_libs: list[Artifact]) -> TemplatePlaceholderInfo: return TemplatePlaceholderInfo(keyed_variables = { "classpath": cmd_args(packaging_info.packaging_deps.project_as_args("full_jar_args"), delimiter = get_path_separator_for_exec_os(ctx)) if packaging_info.packaging_deps else cmd_args(), "classpath_including_targets_with_no_output": cmd_args(packaging_info.packaging_deps.project_as_args("args_for_classpath_macro"), delimiter = get_path_separator_for_exec_os(ctx)), "first_order_classpath": cmd_args(first_order_classpath_libs, delimiter = get_path_separator_for_exec_os(ctx)), }) def create_java_library_providers( ctx: AnalysisContext, library_output: [JavaClasspathEntry, None], global_code_config, declared_deps: list[Dependency] = [], exported_deps: list[Dependency] = [], provided_deps: list[Dependency] = [], exported_provided_deps: list[Dependency] = [], runtime_deps: list[Dependency] = [], needs_desugar: bool = False, is_prebuilt_jar: bool = False, has_srcs: bool = True, sources_jar: Artifact | None = None, generated_sources: list[Artifact] = [], annotation_jars_dir: Artifact | None = None, proguard_config: Artifact | None = None, gwt_module: Artifact | None = None, lint_jar: Artifact | None = None, preprocessed_library: Artifact | None = None, used_jars_json: Artifact | None = None, dex_weight_factor: int = 1) -> (JavaLibraryInfo, JavaPackagingInfo, JavaGlobalCodeInfo, SharedLibraryInfo, ResourceInfo, LinkableGraph, TemplatePlaceholderInfo, JavaLibraryIntellijInfo): first_order_classpath_deps = filter(None, [x.get(JavaLibraryInfo) for x in declared_deps + exported_deps + runtime_deps]) first_order_classpath_libs = [dep.output_for_classpath_macro for dep in first_order_classpath_deps] compiling_deps = derive_compiling_deps(ctx.actions, None, declared_deps + exported_deps + provided_deps + exported_provided_deps) compiling_classpath = [dep.full_library for dep in (list(compiling_deps.traverse()) if compiling_deps else [])] desugar_classpath = compiling_classpath if needs_desugar else [] library_info, packaging_info, global_code_info, shared_library_info, cxx_resource_info, linkable_graph = _create_non_template_providers( ctx, library_output = library_output, global_code_config = global_code_config, declared_deps = declared_deps, exported_deps = exported_deps, exported_provided_deps = exported_provided_deps, runtime_deps = runtime_deps, needs_desugar = needs_desugar, desugar_classpath = desugar_classpath, is_prebuilt_jar = is_prebuilt_jar, has_srcs = has_srcs, sources_jar = sources_jar, proguard_config = proguard_config, gwt_module = gwt_module, first_order_compiling_deps_without_library_itself = compiling_deps, dex_weight_factor = dex_weight_factor, ) first_order_libs = first_order_classpath_libs + [library_info.library_output.full_library] if library_info.library_output else first_order_classpath_libs template_info = create_template_info(ctx, packaging_info, first_order_libs) intellij_info = JavaLibraryIntellijInfo( compiling_classpath = compiling_classpath, generated_sources = generated_sources, annotation_jars_dir = annotation_jars_dir, lint_jar = lint_jar, preprocessed_library = preprocessed_library, used_jars_json = used_jars_json, ) return (library_info, packaging_info, global_code_info, shared_library_info, cxx_resource_info, linkable_graph, template_info, intellij_info)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server