diff --git a/.bazelci/presubmit.yml b/.bazelci/presubmit.yml index 3840395e..4e826dba 100644 --- a/.bazelci/presubmit.yml +++ b/.bazelci/presubmit.yml @@ -10,18 +10,6 @@ build_targets: &build_targets - "@remote_java_tools//:singlejar_cc_bin" # can't build @remote_java_tools_X repos for other platforms - "-//toolchains/..." - # TODO: re-enable docs after moving them out of https://bazel.build/reference/be/java - - "-//java/docs/..." - - "-//test:docs_up_to_date_test" - -build_targets_bazel6: &build_targets_bazel6 - - "//:all" - # build java_tools from source - - "@remote_java_tools//:ijar_cc_binary" - - "@remote_java_tools//:one_version_cc_bin" - - "@remote_java_tools//:proguard" - - "@remote_java_tools//:singlejar_cc_bin" - - "//examples/..." build_targets_integration: &build_targets_integration - "//..." @@ -29,12 +17,6 @@ build_targets_integration: &build_targets_integration test_targets: &test_targets - "//test/..." - # TODO: re-enable docs after moving them out of https://bazel.build/reference/be/java - - "-//test:docs_up_to_date_test" - -test_targets_bazel6: &test_targets_bazel6 - - "//test/java/..." - - "-//test/java/private/..." test_target_integration: &test_target_integration - "//:MyTest" @@ -46,9 +28,9 @@ flags_workspace_integration: &flags_workspace_integration buildifier: latest matrix: - all_platforms: ["ubuntu2004", "macos", "macos_arm64", "windows"] - bazel: ["7.6.1", "8.3.0", "last_green"] # Bazel 6 tested separately, needs different flags - modern_bazel: ["last_green"] # Fully supported Bazel versions + all_platforms: ["rockylinux8_arm64", "ubuntu2004", "macos", "macos_arm64", "windows"] + bazel: ["7.x", "8.x", "9.x", "last_green"] + modern_bazel: ["9.x", "last_green", "rolling"] # Fully supported Bazel versions tasks: # Bazel 9+ @@ -60,8 +42,8 @@ tasks: test_targets: *test_targets # Bazel 8.x build_and_test_bazel8: - name: "Bazel 8.3.0" - bazel: "8.3.0" + name: "Bazel 8.x" + bazel: "8.x" platform: ${{ all_platforms }} build_targets: *build_targets test_targets: *test_targets @@ -69,33 +51,13 @@ tasks: - "--test_tag_filters=-min_bazel_9" # Bazel 7.x build_and_test_bazel7: - name: "Bazel 7.6.1" - bazel: "7.6.1" + name: "Bazel 7.x" + bazel: "7.x" platform: ${{ all_platforms }} build_targets: *build_targets test_targets: *test_targets test_flags: - "--test_tag_filters=-min_bazel_8,-min_bazel_9" -# Bazel 6.x - build_and_test_bazel6: - name: "Bazel 6.5.0" - bazel: 6.5.0 - platform: ${{ all_platforms }} - build_targets: *build_targets_bazel6 - test_targets: *test_targets_bazel6 - test_flags: - - "--test_tag_filters=-min_bazel_7,-min_bazel_8,-min_bazel_9" - ubuntu2004_integration_bazel6: - name: "Integration w/ Bazel 6.5.0" - bazel: 6.5.0 - platform: ${{ all_platforms }} - working_directory: "test/repo" - shell_commands: - - sh setup.sh - batch_commands: - - setup.bat - build_targets: *build_targets_integration - test_targets: *test_target_integration # Integration tests integration_build_and_test: @@ -122,10 +84,9 @@ tasks: build_flags: *flags_workspace_integration test_targets: *test_target_integration test_flags: *flags_workspace_integration -# Linux-only tests - linux_only_tests: - name: "Extra tests w/ Bazel {bazel}" - bazel: ${{ bazel }} + # internal tests for configs and release process + internal_tests: + name: "Internal tests" platform: "ubuntu2004" shell_commands: - "git init" @@ -133,6 +94,8 @@ tasks: - "git commit --allow-empty -m 'Fake init commit'" - "git tag -a 'fake-tag-for-testing' -m 'ignore'" - "git commit --allow-empty -m 'Fake commit message for testing'" + - "git tag -a 'fake-tag-for-testing2' -m 'ignore'" test_targets: - "//test:check_remote_jdk_configs_test" + - "//test:check_remote_java_tools_configs_test" - "//test:check_release_notes_test" diff --git a/.bazelrc b/.bazelrc index 9db5d775..12d684fc 100644 --- a/.bazelrc +++ b/.bazelrc @@ -16,4 +16,7 @@ build --host_cxxopt=-std=c++17 # Some tests relies on dynamic libs that are not interface libs # the latter are always enabled on Windows: https://github.com/bazelbuild/bazel/blob/1f5414408467171581b6142e93f67fe730d722cf/src/main/java/com/google/devtools/build/lib/rules/cpp/CcModule.java#L2430 # we can't use a transition because toolchain deps exceed the default --analysis_testing_deps_limit. -test --nointerface_shared_objects \ No newline at end of file +test --nointerface_shared_objects + +# For testing add_exports/add_opens module flags behavior. +test --incompatible_java_info_merge_runtime_module_flags diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml new file mode 100644 index 00000000..3652a521 --- /dev/null +++ b/.github/workflows/publish.yaml @@ -0,0 +1,32 @@ +name: Publish to BCR +on: + # Run the publish workflow after a successful release + # Will be triggered from the release.yaml workflow + workflow_call: + inputs: + tag_name: + required: true + type: string + # Permit release engineers to retry manually from the GitHub UI + workflow_dispatch: + inputs: + tag_name: + description: git tag being released + required: true + type: string +jobs: + publish: + uses: bazel-contrib/publish-to-bcr/.github/workflows/publish.yaml@v1.1.0 + with: + tag_name: ${{ inputs.tag_name }} + # GitHub repository which is a fork of the upstream where the Pull Request will be opened. + registry_fork: bazel-io/bazel-central-registry + draft: false + attest: true + permissions: + contents: write + id-token: write + attestations: write + secrets: + # Necessary to push to the BCR fork, and to open a pull request against a registry + publish_token: ${{ secrets.BCR_PUBLISH_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..4bfb5090 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,28 @@ +# Automatically perform a release whenever a new "release-like" tag is pushed to the repo. +name: Release + +on: + push: + tags: + # Detect tags that look like a release. + - "*.*.*" +permissions: + id-token: write + attestations: write + contents: write +jobs: + release: + uses: bazel-contrib/.github/.github/workflows/release_ruleset.yaml@v7.3.0 + with: + tag_name: ${{ github.ref_name }} + prerelease: false + draft: false + generate_release_notes: true + release_files: bazel-bin/distro/rules_java-*.tar.gz + bazel_test_command: "bazel test //test/..." + publish: + needs: release + uses: ./.github/workflows/publish.yaml + with: + tag_name: ${{ github.ref_name }} + secrets: inherit diff --git a/.github/workflows/release_prep.sh b/.github/workflows/release_prep.sh new file mode 100755 index 00000000..3173376a --- /dev/null +++ b/.github/workflows/release_prep.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -o errexit -o nounset -o pipefail + +RELEASE_VERSION=${1} + +# update MODULE.bazel with the version number +sed -i "3s/version = \"0.0.0\"/version = \"${RELEASE_VERSION}\"/" MODULE.bazel + +# create release artifacts +bazel build //distro:relnotes //distro:rules_java-${RELEASE_VERSION}.tar.gz + +# revert change to MODULE.bazel +git checkout -- MODULE.bazel + +# print the release notes for release.yaml +cat bazel-bin/distro/relnotes.txt diff --git a/BUILD b/BUILD index 2761f404..2fbbbd62 100644 --- a/BUILD +++ b/BUILD @@ -1,6 +1,7 @@ load("@rules_license//rules:license.bzl", "license") +load("//java:java_test.bzl", "java_test") -package(default_applicable_licenses = ["@rules_java//:license"]) +package(default_applicable_licenses = [":license"]) licenses(["notice"]) @@ -27,3 +28,17 @@ license( name = "license", package_name = "rules_java", ) + +# For exercising root-package behavior in tests +java_test( + name = "invalid_test_at_repo_root", + srcs = ["SomeTest.java"], + tags = [ + "manual", + "nobuilder", + "notap", + ], + visibility = [ + "//test/java/bazel/rules:__pkg__", + ], +) diff --git a/CODEOWNERS b/CODEOWNERS index 1f7a7ed6..9d182e13 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -14,4 +14,4 @@ # Component owners # ---------------- -* @comius @bazelbuild/java-team +* @hvadehra @bazelbuild/java-team diff --git a/MODULE.bazel b/MODULE.bazel index bd4f2111..38405ca6 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,20 +1,30 @@ module( name = "rules_java", - version = "8.14.0", - bazel_compatibility = [">=6.4.0"], + version = "0.0.0", + bazel_compatibility = [">=7.0.0"], compatibility_level = 1, ) bazel_dep(name = "platforms", version = "0.0.11") -bazel_dep(name = "rules_cc", version = "0.0.15") +bazel_dep(name = "rules_cc", version = "0.2.17") bazel_dep(name = "bazel_features", version = "1.30.0") bazel_dep(name = "bazel_skylib", version = "1.6.1") -bazel_dep(name = "protobuf", version = "27.0", repo_name = "com_google_protobuf") +bazel_dep(name = "protobuf", version = "32.1", repo_name = "com_google_protobuf") bazel_dep(name = "zlib", version = "1.3.1.bcr.5") # Required by @remote_java_tools, which is loaded via module extension. bazel_dep(name = "rules_license", version = "0.0.3") -bazel_dep(name = "abseil-cpp", version = "20230802.1", repo_name = "com_google_absl") +bazel_dep(name = "abseil-cpp", version = "20250814.1", repo_name = "com_google_absl") +bazel_dep(name = "re2", version = "2025-11-05.bcr.1") + +single_version_override( + module_name = "protobuf", + patch_strip = 1, + patches = [ + "//third_party:protobuf_load-cc-rules.patch", + ], + version = "32.1", +) register_toolchains("//toolchains:all") @@ -23,6 +33,7 @@ toolchains = use_extension("//java:extensions.bzl", "toolchains") # Declare remote java tools repos use_repo(toolchains, "remote_java_tools") use_repo(toolchains, "remote_java_tools_linux") +use_repo(toolchains, "remote_java_tools_linux_aarch64") use_repo(toolchains, "remote_java_tools_windows") use_repo(toolchains, "remote_java_tools_darwin_x86_64") use_repo(toolchains, "remote_java_tools_darwin_arm64") @@ -80,6 +91,17 @@ JDKS = { "win", "win_arm64", ], + "25": [ + "linux", + "linux_aarch64", + "linux_ppc64le", + "linux_riscv64", + "linux_s390x", + "macos", + "macos_aarch64", + "win", + "win_arm64", + ], } REMOTE_JDK_REPOS = [(("remote_jdk" if version == "8" else "remotejdk") + version + "_" + platform) for version in JDKS for platform in JDKS[version]] @@ -97,15 +119,15 @@ use_repo(compat, "compatibility_proxy") # Dev dependencies bazel_dep(name = "rules_pkg", version = "0.9.1", dev_dependency = True) -bazel_dep(name = "stardoc", version = "0.7.1", dev_dependency = True) +bazel_dep(name = "stardoc", version = "0.8.0", dev_dependency = True) bazel_dep(name = "rules_shell", version = "0.2.0", dev_dependency = True) -bazel_dep(name = "rules_testing", version = "0.7.0", dev_dependency = True) +bazel_dep(name = "rules_testing", dev_dependency = True) archive_override( module_name = "rules_testing", - integrity = "sha256-0+3pLjeZCqn+K1qS7HNr7HbwMXBjxLvJm+pMSUhDel8=", - strip_prefix = "rules_testing-db007bfee840cebcb6f955b80973ba866de38947", - urls = ["https://github.com/bazelbuild/rules_testing/archive/db007bfee840cebcb6f955b80973ba866de38947.tar.gz"], + integrity = "sha256-WYc72jM8jNK3m45vjWlmN6NB+95f6HAHnTkRaSaNisE=", + strip_prefix = "rules_testing-04a1219ee516ccdf3ffadfe3b28e5c634c9b90e1", + urls = ["https://github.com/bazelbuild/rules_testing/archive/04a1219ee516ccdf3ffadfe3b28e5c634c9b90e1.tar.gz"], ) test_repositories = use_extension("//test:repositories.bzl", "test_repositories_ext", dev_dependency = True) -use_repo(test_repositories, "guava", "truth") +use_repo(test_repositories, "guava", "other_repo", "truth") diff --git a/README.md b/README.md index e4cfeb0b..c9d62dc2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # rules_java -* Postsubmit [![Build status](https://badge.buildkite.com/d4f950ef5f481b8ca066624ba06c238fa1446d84a057ddbf89.svg?branch=master)](https://buildkite.com/bazel/rules-java-java) -* Postsubmit + Current Bazel Incompatible Flags [![Build status](https://badge.buildkite.com/ef265d270238c02aff65106a0b861abb9265efacdf4af399c3.svg?branch=master)](https://buildkite.com/bazel/rules-java-plus-bazelisk-migrate) +[![Build status](https://badge.buildkite.com/d4f950ef5f481b8ca066624ba06c238fa1446d84a057ddbf89.svg?branch=master)](https://buildkite.com/bazel/rules-java-java) Java Rules for Bazel https://bazel.build. @@ -9,6 +8,8 @@ Java Rules for Bazel https://bazel.build. For a quickstart tutorial, see https://bazel.build/start/java +The fastest way to try this in an empty project is to click the green "Use this template" button on https://github.com/bazel-starters/java. + For slightly more advanced usage, like setting up toolchains or writing your own java-like rules, see https://bazel.build/docs/bazel-and-java @@ -20,6 +21,6 @@ Add a load like: ```build load("@rules_java//java:java_library.bzl", "java_library") ``` -to your `BUILD` / `BUILD.bazel` / bzl` files +to your `BUILD` / `BUILD.bazel` / `*.bzl` files For detailed docs on the core rules, see https://bazel.build/reference/be/java diff --git a/WORKSPACE b/WORKSPACE index acd7cae0..475e9ef8 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -37,14 +37,21 @@ http_archive( ], ) -load("//java:rules_java_deps.bzl", "rules_java_dependencies") - -rules_java_dependencies() +http_archive( + name = "bazel_features", + sha256 = "a660027f5a87f13224ab54b8dc6e191693c554f2692fcca46e8e29ee7dabc43b", + strip_prefix = "bazel_features-1.30.0", + url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.30.0/bazel_features-v1.30.0.tar.gz", +) load("@bazel_features//:deps.bzl", "bazel_features_deps") bazel_features_deps() +load("//java:rules_java_deps.bzl", "rules_java_dependencies") + +rules_java_dependencies() + load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility proto_bazel_features(name = "proto_bazel_features") diff --git a/distro/relnotes.bzl b/distro/relnotes.bzl index ce04d501..e47c3c95 100644 --- a/distro/relnotes.bzl +++ b/distro/relnotes.bzl @@ -5,7 +5,8 @@ def print_rel_notes(*, name, version, archive): name = name, outs = [name + ".txt"], cmd = """ - last_rel=$$(git describe --tags --abbrev=0) + [ "$$(/usr/bin/git rev-parse --is-shallow-repository)" == "true" ] && /usr/bin/git fetch --unshallow + last_rel=$$(git describe --tags --abbrev=0 HEAD~1) changelog=$$(/usr/bin/git log tags/$$last_rel..HEAD --format=oneline --invert-grep --grep 'ignore-relnotes' --) sha=$$(/usr/bin/sha256sum $(SRCS) | cut -d ' ' -f1) cat > $@ < /dev/stderr - curl --silent --fail -o $$TMP_FILE -L "$$primary_url" > /dev/stderr + curl --retry 5 --write-out '%{{onerror}}%{{url}}\n' --show-error --silent --fail -o $$TMP_FILE -L "$$primary_url" > /dev/stderr sha256=`sha256sum $$TMP_FILE | cut -d' ' -f1` echo "struct(" echo " name = \\"$$name\\"," diff --git a/java/bazel/repositories_util.bzl b/java/bazel/repositories_util.bzl index 38170c13..40101d37 100644 --- a/java/bazel/repositories_util.bzl +++ b/java/bazel/repositories_util.bzl @@ -18,7 +18,7 @@ visibility(["//test"]) _RELEASE_CONFIGS = { "8": { "zulu": { - "release": "8.84.0.15-ca-jdk8.0.442", + "release": "8.90.0.19-ca-jdk8.0.472", "platforms": { "linux": ["aarch64", "x86_64"], "macos": ["aarch64", "x86_64"], @@ -34,7 +34,7 @@ _RELEASE_CONFIGS = { }, "11": { "zulu": { - "release": "11.78.15-ca-jdk11.0.26", + "release": "11.84.17-ca-jdk11.0.29", "platforms": { "linux": ["aarch64", "x86_64"], "macos": ["aarch64", "x86_64"], @@ -42,13 +42,13 @@ _RELEASE_CONFIGS = { }, }, "adoptium": { - "release": "11.0.26+4", + "release": "11.0.28+6", "platforms": { "linux": ["ppc64le", "s390x"], }, }, "microsoft": { - "release": "11.0.26", + "release": "11.0.28", "platforms": { "windows": ["arm64"], }, @@ -56,7 +56,7 @@ _RELEASE_CONFIGS = { }, "17": { "zulu": { - "release": "17.56.15-ca-jdk17.0.14", + "release": "17.62.17-ca-jdk17.0.17", "platforms": { "linux": ["aarch64", "x86_64"], "macos": ["aarch64", "x86_64"], @@ -64,7 +64,7 @@ _RELEASE_CONFIGS = { }, }, "adoptium": { - "release": "17.0.14+7", + "release": "17.0.16+8", "platforms": { "linux": ["ppc64le", "s390x"], }, @@ -72,7 +72,7 @@ _RELEASE_CONFIGS = { }, "21": { "zulu": { - "release": "21.40.17-ca-jdk21.0.6", + "release": "21.46.19-ca-jdk21.0.9", "platforms": { "linux": ["aarch64", "x86_64"], "macos": ["aarch64", "x86_64"], @@ -80,7 +80,23 @@ _RELEASE_CONFIGS = { }, }, "adoptium": { - "release": "21.0.6+7", + "release": "21.0.8+9", + "platforms": { + "linux": ["ppc64le", "riscv64", "s390x"], + }, + }, + }, + "25": { + "zulu": { + "release": "25.32.17-ca-jdk25.0.2", + "platforms": { + "linux": ["aarch64", "x86_64"], + "macos": ["aarch64", "x86_64"], + "windows": ["arm64", "x86_64"], + }, + }, + "adoptium": { + "release": "25.0.2+10", "platforms": { "linux": ["ppc64le", "riscv64", "s390x"], }, @@ -89,7 +105,7 @@ _RELEASE_CONFIGS = { } _STRIP_PREFIX_OVERRIDES = { - "remotejdk11_win_arm64": "jdk-11.0.26+4", + "remotejdk11_win_arm64": "jdk-11.0.28+6", } def _name_for_remote_jdk(version, os, cpu): diff --git a/java/bazel/rules/BUILD.bazel b/java/bazel/rules/BUILD.bazel index e0d79586..108a3f9c 100644 --- a/java/bazel/rules/BUILD.bazel +++ b/java/bazel/rules/BUILD.bazel @@ -23,7 +23,10 @@ filegroup( bzl_library( name = "rules", - srcs = glob(["*.bzl"]), + srcs = glob( + ["*.bzl"], + exclude = ["bazel_java_single_jar.bzl"], + ), visibility = ["//visibility:public"], # for Bazel docgen deps = [ "//java/common:semantics_bzl", @@ -36,6 +39,17 @@ bzl_library( ], ) +bzl_library( + name = "java_single_jar_bzl", + srcs = ["bazel_java_single_jar.bzl"], + visibility = [ + "//java:__pkg__", + ], + deps = [ + "//java/common/rules:java_single_jar_bzl", + ], +) + filegroup( name = "for_bazel_tests", testonly = 1, diff --git a/java/bazel/rules/bazel_java_binary.bzl b/java/bazel/rules/bazel_java_binary.bzl index da547226..4ee9c881 100644 --- a/java/bazel/rules/bazel_java_binary.bzl +++ b/java/bazel/rules/bazel_java_binary.bzl @@ -24,12 +24,12 @@ load( load("//java/common/rules:java_binary.bzl", "BASIC_JAVA_BINARY_ATTRIBUTES") load("//java/common/rules:rule_util.bzl", "merge_attrs") load("//java/common/rules/impl:java_binary_deploy_jar.bzl", "create_deploy_archives") -load("//java/common/rules/impl:java_binary_impl.bzl", "basic_java_binary") +load("//java/common/rules/impl:java_binary_impl.bzl", "basic_java_binary", "binary_provider_helper") load("//java/common/rules/impl:java_helper.bzl", "helper") load("//java/private:java_info.bzl", "JavaInfo") def _bazel_java_binary_impl(ctx): - return bazel_base_binary_impl(ctx, is_test_rule_class = False) + helper.executable_providers(ctx) + return bazel_base_binary_impl(ctx, is_test_rule_class = False) + binary_provider_helper.executable_providers(ctx) def bazel_base_binary_impl(ctx, is_test_rule_class): """Common implementation for binaries and tests @@ -84,7 +84,7 @@ def bazel_base_binary_impl(ctx, is_test_rule_class): test_class = helper.primary_class(ctx) if test_class == None: fail("cannot determine test class. You might want to rename the " + - " rule or add a 'test_class' attribute.") + "rule or add a 'test_class' attribute.") jvm_flags.extend([ "-ea", "-Dbazel.test_suite=" + helper.shell_escape(test_class), @@ -232,7 +232,7 @@ def _create_stub(ctx, java_attrs, launcher, executable, jvm_flags, main_class, c jvm_flags_for_launcher = [] for flag in jvm_flags: jvm_flags_for_launcher.extend(ctx.tokenize(flag)) - return _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, executable) + return _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, coverage_enabled, executable, coverage_main_class) if runfiles_enabled: prefix = "" if helper.is_absolute_target_platform_path(ctx, java_executable) else "${JAVA_RUNFILES}/" @@ -277,13 +277,15 @@ def _format_classpath_entry(runfiles_enabled, workspace_prefix, file): return "$(rlocation " + paths.normalize(workspace_prefix + file.short_path) + ")" -def _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, executable): +def _create_windows_exe_launcher(ctx, java_executable, classpath, main_class, jvm_flags_for_launcher, runfiles_enabled, coverage_enabled, executable, coverage_main_class): launch_info = ctx.actions.args().use_param_file("%s", use_always = True).set_param_file_format("multiline") launch_info.add("binary_type=Java") launch_info.add(ctx.workspace_name, format = "workspace_name=%s") launch_info.add("1" if runfiles_enabled else "0", format = "symlink_runfiles_enabled=%s") launch_info.add(java_executable, format = "java_bin_path=%s") launch_info.add(main_class, format = "java_start_class=%s") + if coverage_enabled: + launch_info.add(coverage_main_class, format = "jacoco_main_class=%s") launch_info.add_joined(classpath, map_each = _short_path, join_with = ";", format_joined = "classpath=%s", omit_if_empty = False) launch_info.add_joined(jvm_flags_for_launcher, join_with = "\t", format_joined = "jvm_flags=%s", omit_if_empty = False) launch_info.add(semantics.find_java_runtime_toolchain(ctx).java_home_runfiles_path, format = "jar_bin_path=%s/bin/jar.exe") diff --git a/java/bazel/rules/bazel_java_single_jar.bzl b/java/bazel/rules/bazel_java_single_jar.bzl new file mode 100644 index 00000000..922fb638 --- /dev/null +++ b/java/bazel/rules/bazel_java_single_jar.bzl @@ -0,0 +1,21 @@ +# Copyright 2026 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Bazel java_single_jar rule""" + +load("//java/common/rules:java_single_jar.bzl", _bazel_java_single_jar = "bazel_java_single_jar") + +def java_single_jar(*, name, **kwargs): + if "output" not in kwargs: + kwargs["output"] = name + ".jar" + _bazel_java_single_jar(name = name, **kwargs) diff --git a/java/bazel/rules/bazel_java_test.bzl b/java/bazel/rules/bazel_java_test.bzl index fd3e2bd2..061c058e 100644 --- a/java/bazel/rules/bazel_java_test.bzl +++ b/java/bazel/rules/bazel_java_test.bzl @@ -16,11 +16,11 @@ load("//java/common:java_semantics.bzl", "semantics") load("//java/common/rules:java_binary.bzl", "BASE_TEST_ATTRIBUTES") load("//java/common/rules:rule_util.bzl", "merge_attrs") -load("//java/common/rules/impl:java_helper.bzl", "helper") +load("//java/common/rules/impl:java_binary_impl.bzl", "binary_provider_helper") load(":bazel_java_binary.bzl", "BASE_BINARY_ATTRS", "bazel_base_binary_impl", "make_binary_rule") def _bazel_java_test_impl(ctx): - return bazel_base_binary_impl(ctx, is_test_rule_class = True) + helper.test_providers(ctx) + return bazel_base_binary_impl(ctx, is_test_rule_class = True) + binary_provider_helper.test_providers(ctx) def _java_test_initializer(**kwargs): if "stamp" in kwargs and type(kwargs["stamp"]) == type(True): diff --git a/java/common/BUILD b/java/common/BUILD index 9958a883..7887b1f0 100644 --- a/java/common/BUILD +++ b/java/common/BUILD @@ -37,7 +37,8 @@ bzl_library( srcs = ["java_semantics.bzl"], visibility = ["//visibility:public"], deps = [ - "@rules_cc//cc/common", + "@bazel_features//:features", + "@rules_cc//cc/common:cc_helper_bzl", ], ) diff --git a/java/common/java_semantics.bzl b/java/common/java_semantics.bzl index 700c0d1d..919553e9 100644 --- a/java/common/java_semantics.bzl +++ b/java/common/java_semantics.bzl @@ -13,6 +13,8 @@ # limitations under the License. """Bazel Java Semantics""" +load("@bazel_features//private:util.bzl", _bazel_version_ge = "ge") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/common:cc_helper.bzl", "cc_helper") # copybara: default visibility @@ -23,6 +25,9 @@ def _find_java_toolchain(ctx): def _find_java_runtime_toolchain(ctx): return ctx.toolchains["@bazel_tools//tools/jdk:runtime_toolchain_type"].java_runtime +def _update_args_for_import_deps(*_args): + pass + def _get_default_resource_path(path, segment_extractor): # Look for src/.../resources to match Maven repository structure. segments = path.split("/") @@ -41,6 +46,10 @@ def _check_java_info_opens_exports(): def _minimize_cc_info(cc_info): return cc_info +def _merge_cc_infos(*args, **kwargs): + # TODO: b/483025864 - use https://github.com/bazelbuild/rules_cc/commit/011d6d9e7fae71d43df2d4d83c577f2cef2aa52e + return cc_common.merge_cc_infos(*args, **kwargs) + _DOCS = struct( ATTRS = { "resources": """ @@ -105,12 +114,18 @@ semantics = struct( compatible_javac_options = _compatible_javac_options, LAUNCHER_FLAG_LABEL = Label("@bazel_tools//tools/jdk:launcher_flag_alias"), PROGUARD_ALLOWLISTER_LABEL = "@bazel_tools//tools/jdk:proguard_whitelister", + TOOLS_TEST_DEFAULT_TEST_TOOLCHAIN_TYPE = "@bazel_tools//tools/test:default_test_toolchain_type", + TOOLS_TEST_EMPTY_TOOLCHAIN = "@bazel_tools//tools/test:empty_toolchain", check_java_info_opens_exports = _check_java_info_opens_exports, DOCS = struct( for_attribute = lambda name: _DOCS.ATTRS.get(name, ""), ), minimize_cc_info = _minimize_cc_info, + merge_cc_infos = _merge_cc_infos, tokenize_javacopts = _tokenize_javacopts, PLATFORMS_ROOT = "@platforms//", INCOMPATIBLE_DISABLE_NON_EXECUTABLE_JAVA_BINARY = False, # Flip when java_single_jar is feature complete + update_args_for_import_deps = _update_args_for_import_deps, + expand_javacopts_make_variables = True, + java_toolchain_supports_one_version = _bazel_version_ge("8.0.0"), # can be dropped once we no longer support Bazel 7 ) diff --git a/java/common/rules/BUILD b/java/common/rules/BUILD index 12006384..4c24d073 100644 --- a/java/common/rules/BUILD +++ b/java/common/rules/BUILD @@ -25,6 +25,23 @@ bzl_library( visibility = ["//visibility:private"], ) +bzl_library( + name = "java_helper_bzl", + srcs = ["java_helper.bzl"], + visibility = ["//java:__subpackages__"], +) + +bzl_library( + name = "java_single_jar_bzl", + srcs = ["java_single_jar.bzl"], + visibility = ["//java:__subpackages__"], + deps = [ + "//java/common", + "//java/common:semantics_bzl", + "//java/common/rules/impl:java_helper_bzl", + ], +) + bzl_library( name = "core_rules", srcs = [ @@ -58,6 +75,15 @@ bzl_library( "//java:__subpackages__", "@compatibility_proxy//:__pkg__", ], + deps = [ + ":java_helper_bzl", + "//java/common:semantics_bzl", + "//java/private:boot_class_path_info_bzl", + "//java/private:java_info_bzl", + "//java/private:native_bzl", + "@bazel_skylib//lib:paths", + "@rules_cc//cc/common", + ], ) filegroup( @@ -66,6 +92,7 @@ filegroup( srcs = [ "BUILD", ":core_rules", + ":java_single_jar_bzl", ":toolchain_rules", "//java/common/rules/impl:for_bazel_tests", "@rules_cc//cc/private/rules_impl:srcs", diff --git a/java/common/rules/android_lint.bzl b/java/common/rules/android_lint.bzl index f0a04328..7152990c 100644 --- a/java/common/rules/android_lint.bzl +++ b/java/common/rules/android_lint.bzl @@ -22,7 +22,18 @@ def _tokenize_opts(opts_depset): opts = reversed(opts_depset.to_list()) return semantics.tokenize_javacopts(opts) -def _android_lint_action(ctx, source_files, source_jars, compilation_info): +def _flags_from_disable_lint_checks(args, disable_lint_checks): + invalid_ids = [check for check in disable_lint_checks if not _check_id_is_valid(check)] + if invalid_ids: + fail("Found not allowed character in disabled check ID(s) %s" % str(invalid_ids)) + args.add_joined("--disable", disable_lint_checks, join_with = ",") + +# Returns whether the passed Android Lint check ID is valid +def _check_id_is_valid(check): + # We want to prevent whitespace so that extra flags can't be 'injected' into Android Lint + return check.replace(".", "").replace("_", "").isalnum() + +def _android_lint_action(ctx, source_files, source_jars, compilation_info, is_library, disable_lint_checks = []): """ Creates an action that runs Android lint against Java source files. @@ -42,6 +53,8 @@ def _android_lint_action(ctx, source_files, source_jars, compilation_info): source_jars: (list[File]) A list of .jar or .srcjar files containing source files. It should also include generated source jars. compilation_info: (struct) Information about compilation. + is_library: (bool) Whether the target is a library. + disable_lint_checks: (list[str]) A list of AndroidLint checks to be skipped. Returns: (None|File) The Android lint output file or None if no source files were @@ -101,6 +114,7 @@ def _android_lint_action(ctx, source_files, source_jars, compilation_info): args.add_all("--classpath", classpath) args.add_all("--lint_rules", compilation_info.plugins.processor_jars) args.add("--target_label", ctx.label) + args.add("--library", str(is_library).lower()) javac_opts = compilation_info.javac_options if javac_opts: @@ -110,6 +124,7 @@ def _android_lint_action(ctx, source_files, source_jars, compilation_info): args.add("--lintopts") args.add_all(linter.lint_opts) + _flags_from_disable_lint_checks(args, disable_lint_checks) for package_config in linter.package_config: if package_config.matches(package_config.package_specs, ctx.label): diff --git a/java/common/rules/impl/BUILD b/java/common/rules/impl/BUILD index 65c5af86..70adeccd 100644 --- a/java/common/rules/impl/BUILD +++ b/java/common/rules/impl/BUILD @@ -22,6 +22,7 @@ bzl_library( ":java_helper_bzl", "//java/common:proguard_spec_info_bzl", "@com_google_protobuf//bazel/common:proto_info_bzl", + "@rules_cc//cc/common:cc_helper_bzl", ], ) @@ -29,6 +30,13 @@ bzl_library( name = "java_helper_bzl", srcs = ["java_helper.bzl"], visibility = ["//java:__subpackages__"], + deps = [ + "//java/common:semantics_bzl", + "//java/common/rules:java_helper_bzl", + "@bazel_skylib//lib:paths", + "@rules_cc//cc:find_cc_toolchain_bzl", + "@rules_cc//cc/common", + ], ) filegroup( diff --git a/java/common/rules/impl/basic_java_library_impl.bzl b/java/common/rules/impl/basic_java_library_impl.bzl index cf7c5c19..e2e27442 100644 --- a/java/common/rules/impl/basic_java_library_impl.bzl +++ b/java/common/rules/impl/basic_java_library_impl.bzl @@ -71,7 +71,9 @@ def basic_java_library( add_exports = [], add_opens = [], bootclasspath = None, - javabuilder_jvm_flags = None): + javabuilder_jvm_flags = None, + is_library = True, + disable_lint_checks = []): """ Creates actions that compile and lint Java sources, sets up coverage and returns JavaInfo, InstrumentedFilesInfo and output groups. @@ -107,6 +109,8 @@ def basic_java_library( add_opens: (list[str]) Allow this library to reflectively access the given /. bootclasspath: (Target) The JDK APIs to compile this library against. javabuilder_jvm_flags: (list[str]) Additional JVM flags to pass to JavaBuilder. + is_library: (bool) Whether the target is a library. Primarily for static analysis purposes. + disable_lint_checks: (list[str]) A list of AndroidLint checks to be skipped. Returns: (dict[str, Provider], {files_to_build: list[File], @@ -158,7 +162,8 @@ def basic_java_library( validation_outputs = [] - if ctx.fragments.java.run_android_lint: + # Validation actions don't run in the exec config, so no need to create them. + if ctx.fragments.java.run_android_lint and not ctx.configuration.is_tool_configuration(): generated_source_jars = [ output.generated_source_jar for output in java_info.java_outputs @@ -168,6 +173,8 @@ def basic_java_library( source_files, source_jars + generated_source_jars, compilation_info, + is_library, + disable_lint_checks, ) if lint_output: validation_outputs.append(depset([lint_output])) diff --git a/java/common/rules/impl/bazel_java_import_impl.bzl b/java/common/rules/impl/bazel_java_import_impl.bzl index ce338cbd..c402fc44 100644 --- a/java/common/rules/impl/bazel_java_import_impl.bzl +++ b/java/common/rules/impl/bazel_java_import_impl.bzl @@ -63,37 +63,16 @@ def _process_with_ijars_if_needed(jars, ctx): return file_dict -def _check_export_error(ctx, exports): - not_in_allowlist = hasattr(ctx.attr, "_allowlist_java_import_exports") and not getattr(ctx.attr, "_allowlist_java_import_exports")[PackageSpecificationInfo].contains(ctx.label) +def _check_export_error(ctx, exports, permit_exports): disallow_java_import_exports = ctx.fragments.java.disallow_java_import_exports() - if len(exports) != 0 and (disallow_java_import_exports or not_in_allowlist): + if len(exports) != 0 and (disallow_java_import_exports or not permit_exports): fail("java_import.exports is no longer supported; use java_import.deps instead") def _check_empty_jars_error(ctx, jars): if len(jars) == 0: fail("empty java_import.jars is not supported " + ctx.label.package) -def _create_java_info_with_dummy_output_file(ctx, srcjar, all_deps, exports, runtime_deps_list, neverlink, cc_info_list, add_exports, add_opens): - dummy_jar = ctx.actions.declare_file(ctx.label.name + "_dummy.jar") - dummy_src_jar = srcjar - if dummy_src_jar == None: - dummy_src_jar = ctx.actions.declare_file(ctx.label.name + "_src_dummy.java") - ctx.actions.write(dummy_src_jar, "") - return java_common.compile( - ctx, - output = dummy_jar, - java_toolchain = semantics.find_java_toolchain(ctx), - source_files = [dummy_src_jar], - deps = all_deps, - runtime_deps = runtime_deps_list, - neverlink = neverlink, - exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. - native_libraries = cc_info_list, - add_exports = add_exports, - add_opens = add_opens, - ) - def bazel_java_import_rule( ctx, jars = [], @@ -104,7 +83,9 @@ def bazel_java_import_rule( neverlink = False, proguard_specs = [], add_exports = [], - add_opens = []): + add_opens = [], + permit_exports = True, + skip_incomplete_deps_check = True): """Implements java_import. This rule allows the use of precompiled .jar files as libraries in other Java rules. @@ -120,6 +101,8 @@ def bazel_java_import_rule( proguard_specs: (list[File]) Files to be used as Proguard specification. add_exports: (list[str]) Allow this library to access the given /. add_opens: (list[str]) Allow this library to reflectively access the given /. + permit_exports: (bool) Allow using exports + skip_incomplete_deps_check: (bool) If this target is allowed to have incomplete deps Returns: (list[provider]) A list containing DefaultInfo, JavaInfo, @@ -127,15 +110,14 @@ def bazel_java_import_rule( """ _check_empty_jars_error(ctx, jars) - _check_export_error(ctx, exports) + _check_export_error(ctx, exports, permit_exports) collected_jars = _collect_jars(ctx, jars) all_deps = _filter_provider(JavaInfo, deps, exports) jdeps_artifact = None merged_java_info = java_common.merge(all_deps) - not_in_allowlist = hasattr(ctx.attr, "_allowlist_java_import_deps_checking") and not ctx.attr._allowlist_java_import_deps_checking[PackageSpecificationInfo].contains(ctx.label) - if len(collected_jars) > 0 and not_in_allowlist and "incomplete-deps" not in ctx.attr.tags: + if not skip_incomplete_deps_check and "incomplete-deps" not in ctx.attr.tags: jdeps_artifact = import_deps_check( ctx, collected_jars, @@ -147,26 +129,21 @@ def bazel_java_import_rule( compilation_to_runtime_jar_map = _process_with_ijars_if_needed(collected_jars, ctx) runtime_deps_list = [runtime_dep[JavaInfo] for runtime_dep in runtime_deps if JavaInfo in runtime_dep] cc_info_list = [dep[CcInfo] for dep in deps if CcInfo in dep] - java_info = None - if len(collected_jars) > 0: - java_infos = [] - for jar in collected_jars: - java_infos.append(JavaInfo( - output_jar = jar, - compile_jar = compilation_to_runtime_jar_map[jar], - deps = all_deps, - runtime_deps = runtime_deps_list, - neverlink = neverlink, - source_jar = srcjar, - exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. - native_libraries = cc_info_list, - add_exports = add_exports, - add_opens = add_opens, - )) - java_info = java_common.merge(java_infos) - else: - # TODO(kotlaja): Remove next line once all java_import targets with empty jars attribute are cleaned from depot (b/246559727). - java_info = _create_java_info_with_dummy_output_file(ctx, srcjar, all_deps, exports, runtime_deps_list, neverlink, cc_info_list, add_exports, add_opens) + java_infos = [] + for jar in collected_jars: + java_infos.append(JavaInfo( + output_jar = jar, + compile_jar = compilation_to_runtime_jar_map[jar], + deps = all_deps, + runtime_deps = runtime_deps_list, + neverlink = neverlink, + source_jar = srcjar, + exports = [export[JavaInfo] for export in exports if JavaInfo in export], # Watchout, maybe you need to add them there manually. + native_libraries = cc_info_list, + add_exports = add_exports, + add_opens = add_opens, + )) + java_info = java_common.merge(java_infos) target = {"JavaInfo": java_info} @@ -190,11 +167,18 @@ def bazel_java_import_rule( ) output_group_src_jars = depset() if srcjar == None else depset([srcjar]) + + validation_group = [] + if jdeps_artifact != None: + validation_group.append(jdeps_artifact) + if srcjar != None: + validation_group.append(srcjar) + target["OutputGroupInfo"] = OutputGroupInfo( **{ "_source_jars": output_group_src_jars, "_direct_source_jars": output_group_src_jars, - "_validation": depset() if jdeps_artifact == None else depset([jdeps_artifact]), + "_validation": depset(validation_group), "_hidden_top_level_INTERNAL_": target["ProguardSpecProvider"].specs, } ) diff --git a/java/common/rules/impl/bazel_java_library_impl.bzl b/java/common/rules/impl/bazel_java_library_impl.bzl index 5c7fc5cb..3ee1deb7 100644 --- a/java/common/rules/impl/bazel_java_library_impl.bzl +++ b/java/common/rules/impl/bazel_java_library_impl.bzl @@ -35,7 +35,8 @@ def bazel_java_library_rule( add_exports = [], add_opens = [], bootclasspath = None, - javabuilder_jvm_flags = None): + javabuilder_jvm_flags = None, + disable_lint_checks = []): """Implements java_library. Use this call when you need to produce a fully fledged java_library from @@ -58,6 +59,7 @@ def bazel_java_library_rule( add_opens: (list[str]) Allow this library to reflectively access the given /. bootclasspath: (Target) The JDK APIs to compile this library against. javabuilder_jvm_flags: (list[str]) Additional JVM flags to pass to JavaBuilder. + disable_lint_checks: (list[str]) A list of AndroidLint checks to be skipped. Returns: (dict[str, provider]) A list containing DefaultInfo, JavaInfo, InstrumentedFilesInfo, OutputGroupsInfo, ProguardSpecProvider providers. @@ -83,6 +85,7 @@ def bazel_java_library_rule( add_opens = add_opens, bootclasspath = bootclasspath, javabuilder_jvm_flags = javabuilder_jvm_flags, + disable_lint_checks = disable_lint_checks, ) target["DefaultInfo"] = construct_defaultinfo( diff --git a/java/common/rules/impl/compile_action.bzl b/java/common/rules/impl/compile_action.bzl index bf5b9359..f553a837 100644 --- a/java/common/rules/impl/compile_action.bzl +++ b/java/common/rules/impl/compile_action.bzl @@ -135,7 +135,10 @@ def compile_action( Files_to_build may include an empty .jar file when there are no sources or resources present, whereas runfiles in this case are empty. """ - + expanded_javacopts = javacopts + expanded_javacopts = [ctx.expand_location(opt) for opt in expanded_javacopts] + if semantics.expand_javacopts_make_variables: + expanded_javacopts = [ctx.expand_make_variables("javacopts", opt, {}) for opt in expanded_javacopts] java_info = _compile_private_for_builtins( ctx, output = output_class_jar, @@ -151,7 +154,7 @@ def compile_action( runtime_deps = runtime_deps, exports = exports, exported_plugins = exported_plugins, - javac_opts = [ctx.expand_location(opt) for opt in javacopts], + javac_opts = expanded_javacopts, neverlink = neverlink, output_source_jar = output_source_jar, strict_deps = _filter_strict_deps(strict_deps), diff --git a/java/common/rules/impl/import_deps_check.bzl b/java/common/rules/impl/import_deps_check.bzl index 68d52145..69dec8b6 100644 --- a/java/common/rules/impl/import_deps_check.bzl +++ b/java/common/rules/impl/import_deps_check.bzl @@ -57,6 +57,7 @@ def import_deps_check( args.add("--jdeps_output", jdeps_output) args.add("--rule_label", ctx.label) + semantics.update_args_for_import_deps(ctx, args) inputs = depset( jars_to_check, transitive = [ diff --git a/java/common/rules/impl/java_binary_deploy_jar.bzl b/java/common/rules/impl/java_binary_deploy_jar.bzl index 8755d959..d6add141 100644 --- a/java/common/rules/impl/java_binary_deploy_jar.bzl +++ b/java/common/rules/impl/java_binary_deploy_jar.bzl @@ -19,15 +19,6 @@ load(":java_helper.bzl", "helper") # copybara: default visibility -def _get_build_info(ctx, stamp): - if helper.is_stamping_enabled(ctx, stamp): - # Makes the target depend on BUILD_INFO_KEY, which helps to discover stamped targets - # See b/326620485 for more details. - ctx.version_file # buildifier: disable=no-effect - return ctx.attr._build_info_translator[OutputGroupInfo].non_redacted_build_info_files.to_list() - else: - return ctx.attr._build_info_translator[OutputGroupInfo].redacted_build_info_files.to_list() - def create_deploy_archives( ctx, java_attrs, @@ -70,7 +61,7 @@ def create_deploy_archives( order = "preorder", ) multi_release = ctx.fragments.java.multi_release_deploy_jars - build_info_files = _get_build_info(ctx, ctx.attr.stamp) + build_info_files = helper.get_build_info(ctx, ctx.attr.stamp) build_target = str(ctx.label) manifest_lines = ctx.attr.deploy_manifest_lines + extra_manifest_lines create_deploy_archive( @@ -182,6 +173,7 @@ def create_deploy_archive( args.add("--build_target", build_target) args.add("--normalize") args.add("--compression") + args.add("--nocompress_suffixes", "protobuf.meta") if main_class: args.add("--main_class", main_class) args.add_all("--deploy_manifest_lines", manifest_lines) diff --git a/java/common/rules/impl/java_binary_impl.bzl b/java/common/rules/impl/java_binary_impl.bzl index a41a125b..8b9b68de 100644 --- a/java/common/rules/impl/java_binary_impl.bzl +++ b/java/common/rules/impl/java_binary_impl.bzl @@ -16,6 +16,7 @@ load("@com_google_protobuf//bazel/common:proto_info.bzl", "ProtoInfo") load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/common:cc_helper.bzl", "cc_helper") load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load("//java/common:java_semantics.bzl", "semantics") load("//java/common/rules/impl:basic_java_library_impl.bzl", "basic_java_library", "collect_deps") @@ -117,6 +118,7 @@ def basic_java_binary( add_exports = ctx.attr.add_exports, add_opens = ctx.attr.add_opens, bootclasspath = ctx.attr.bootclasspath, + is_library = False, ) java_info = target["JavaInfo"] compilation_info = java_info.compilation_info @@ -154,7 +156,10 @@ def basic_java_binary( if JavaInfo in dep: native_libs_depsets.append(dep[JavaInfo].transitive_native_libraries) if CcInfo in dep: - native_libs_depsets.append(dep[CcInfo].transitive_native_libraries()) + if hasattr(dep[CcInfo], "_legacy_transitive_native_libraries"): + native_libs_depsets.append(dep[CcInfo]._legacy_transitive_native_libraries) + else: + native_libs_depsets.append(dep[CcInfo].transitive_native_libraries()) native_libs_dirs = collect_native_deps_dirs(depset(transitive = native_libs_depsets)) if native_libs_dirs: prefix = "${JAVA_RUNFILES}/" + ctx.workspace_name + "/" @@ -465,3 +470,34 @@ def _auto_create_deploy_jar(ctx, info, launcher_info, main_class, coverage_main_ add_opens = info.add_opens, ) return output + +def _test_providers(ctx): + test_providers = [] + if helper.has_target_constraints(ctx, ctx.attr._apple_constraints): + test_providers.append(testing.ExecutionInfo({"requires-darwin": ""})) + + test_env = {} + test_env.update(cc_helper.get_expanded_env(ctx, {})) + + coverage_config = helper.get_coverage_config( + ctx, + runner = None, # we only need the environment + ) + if coverage_config: + test_env.update(coverage_config.env) + test_providers.append(testing.TestEnvironment( + environment = test_env, + inherited_environment = ctx.attr.env_inherit, + )) + + return test_providers + +def _executable_providers(ctx): + if ctx.attr.create_executable: + return [RunEnvironmentInfo(cc_helper.get_expanded_env(ctx, {}))] + return [] + +binary_provider_helper = struct( + executable_providers = _executable_providers, + test_providers = _test_providers, +) diff --git a/java/common/rules/impl/java_helper.bzl b/java/common/rules/impl/java_helper.bzl index c97d0060..638878ba 100644 --- a/java/common/rules/impl/java_helper.bzl +++ b/java/common/rules/impl/java_helper.bzl @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""Common util functions for java_* rules""" +"""Common util functions for java_* rules implementations""" load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cc_toolchain") load("@rules_cc//cc/common:cc_common.bzl", "cc_common") -load("@rules_cc//cc/common:cc_helper.bzl", "cc_helper") load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", _loading_phase_helper = "helper") # copybara: rules_java visibility @@ -94,50 +94,18 @@ def _primary_class(ctx): for src in ctx.files.srcs: if src.basename == main: return _full_classname(_strip_extension(src)) - return _full_classname(_get_relative(ctx.label.package, ctx.label.name)) + return _full_classname(helper.get_relative(ctx.label.package, ctx.label.name)) def _strip_extension(file): return file.dirname + "/" + ( file.basename[:-(1 + len(file.extension))] if file.extension else file.basename ) -# TODO(b/193629418): once out of builtins, create a canonical implementation and remove duplicates in depot +# TODO(b/465048589): once out of builtins, create a canonical implementation and remove duplicates in depot def _full_classname(path): - java_segments = _java_segments(path) + java_segments = _loading_phase_helper.java_segments(path) return ".".join(java_segments) if java_segments != None else None -def _java_segments(path): - if path.startswith("/"): - fail("path must not be absolute: '%s'" % path) - segments = path.split("/") - root_idx = -1 - for idx, segment in enumerate(segments): - if segment in ["java", "javatests", "src", "testsrc"]: - root_idx = idx - break - if root_idx < 0: - return None - is_src = "src" == segments[root_idx] - check_mvn_idx = root_idx if is_src else -1 - if (root_idx == 0 or is_src): - for i in range(root_idx + 1, len(segments) - 1): - segment = segments[i] - if "src" == segment or (is_src and (segment in ["java", "javatests"])): - next = segments[i + 1] - if next in ["com", "org", "net"]: - root_idx = i - elif "src" == segment: - check_mvn_idx = i - break - - if check_mvn_idx >= 0 and check_mvn_idx < len(segments) - 2: - next = segments[check_mvn_idx + 1] - if next in ["main", "test"]: - next = segments[check_mvn_idx + 2] - if next in ["java", "resources"]: - root_idx = check_mvn_idx + 2 - return segments[(root_idx + 1):] - def _concat(*lists): result = [] for list in lists: @@ -171,18 +139,15 @@ def _get_shared_native_deps_path( method below is only ensured by validations in the CppLinkAction.Builder.build() method. """ - fp = "" - for artifact in linker_inputs: - fp += artifact.short_path - fp += str(len(link_opts)) - for opt in link_opts: - fp += opt - for artifact in linkstamps: - fp += artifact.short_path - for artifact in build_info_artifacts: - fp += artifact.short_path - for feature in features: - fp += feature + fp = [] + + # join() is faster than concatenating many strings individually + fp += [a.short_path for a in linker_inputs] + fp.append(str(len(link_opts))) + fp += link_opts + fp += [a.short_path for a in linkstamps] + fp += [a.short_path for a in build_info_artifacts] + fp += features # Sharing of native dependencies may cause an ActionConflictException when ThinLTO is # disabled for test and test-only targets that are statically linked, but enabled for other @@ -191,9 +156,9 @@ def _get_shared_native_deps_path( # this, we allow creation of multiple artifacts for the shared native library - one shared # among the test and test-only targets where ThinLTO is disabled, and the other shared among # other targets where ThinLTO is enabled. - fp += "1" if is_test_target_partially_disabled_thin_lto else "0" + fp.append("1" if is_test_target_partially_disabled_thin_lto else "0") - fingerprint = "%x" % hash(fp) + fingerprint = "%x" % hash("".join(fp)) return "_nativedeps/" + fingerprint def _check_and_get_one_version_attribute(ctx, attr): @@ -203,7 +168,7 @@ def _check_and_get_one_version_attribute(ctx, attr): def _jar_and_target_arg_mapper(jar): # Emit pretty labels for targets in the main repository. label = str(jar.owner) - if label.startswith("@@//"): + if label.startswith("@@//"): # buildifier: disable=canonical-repository label = label.lstrip("@") return jar.path + "," + label @@ -254,19 +219,8 @@ def _get_java_executable(ctx, java_runtime_toolchain, launcher): java_executable = ctx.workspace_name + "/" + java_executable return paths.normalize(java_executable) -def _has_target_constraints(ctx, constraints): - # Constraints is a label_list. - for constraint in constraints: - constraint_value = constraint[platform_common.ConstraintValueInfo] - if ctx.target_platform_has_constraint(constraint_value): - return True - return False - -def _is_target_platform_windows(ctx): - return _has_target_constraints(ctx, ctx.attr._windows_constraints) - def _is_absolute_target_platform_path(ctx, path): - if _is_target_platform_windows(ctx): + if helper.is_target_platform_windows(ctx): return len(path) > 2 and path[1] == ":" return path.startswith("/") @@ -278,165 +232,6 @@ def _get_test_support(ctx): return ctx.attr._test_support return None -def _test_providers(ctx): - test_providers = [] - if _has_target_constraints(ctx, ctx.attr._apple_constraints): - test_providers.append(testing.ExecutionInfo({"requires-darwin": ""})) - - test_env = {} - test_env.update(cc_helper.get_expanded_env(ctx, {})) - - coverage_config = _get_coverage_config( - ctx, - runner = None, # we only need the environment - ) - if coverage_config: - test_env.update(coverage_config.env) - test_providers.append(testing.TestEnvironment( - environment = test_env, - inherited_environment = ctx.attr.env_inherit, - )) - - return test_providers - -def _executable_providers(ctx): - if ctx.attr.create_executable: - return [RunEnvironmentInfo(cc_helper.get_expanded_env(ctx, {}))] - return [] - -def _resource_mapper(file): - root_relative_path = paths.relativize( - path = file.path, - start = paths.join(file.root.path, file.owner.workspace_root), - ) - return "%s:%s" % ( - file.path, - semantics.get_default_resource_path(root_relative_path, segment_extractor = _java_segments), - ) - -def _create_single_jar( - actions, - toolchain, - output, - sources = depset(), - resources = depset(), - mnemonic = "JavaSingleJar", - progress_message = "Building singlejar jar %{output}", - build_target = None, - output_creator = None): - """Register singlejar action for the output jar. - - Args: - actions: (actions) ctx.actions - toolchain: (JavaToolchainInfo) The java toolchain - output: (File) Output file of the action. - sources: (depset[File]) The jar files to merge into the output jar. - resources: (depset[File]) The files to add to the output jar. - mnemonic: (str) The action identifier - progress_message: (str) The action progress message - build_target: (Label) The target label to stamp in the manifest. Optional. - output_creator: (str) The name of the tool to stamp in the manifest. Optional, - defaults to 'singlejar' - Returns: - (File) Output file which was used for registering the action. - """ - args = actions.args() - args.set_param_file_format("shell").use_param_file("@%s", use_always = True) - args.add("--output", output) - args.add_all( - [ - "--compression", - "--normalize", - "--exclude_build_data", - "--warn_duplicate_resources", - ], - ) - args.add_all("--sources", sources) - args.add_all("--resources", resources, map_each = _resource_mapper) - - args.add("--build_target", build_target) - args.add("--output_jar_creator", output_creator) - - actions.run( - mnemonic = mnemonic, - progress_message = progress_message, - executable = toolchain.single_jar, - toolchain = semantics.JAVA_TOOLCHAIN_TYPE, - inputs = depset(transitive = [resources, sources]), - tools = [toolchain.single_jar], - outputs = [output], - arguments = [args], - use_default_shell_env = True, - ) - return output - -# TODO(hvd): use skylib shell.quote() -def _shell_escape(s): - """Shell-escape a string - - Quotes a word so that it can be used, without further quoting, as an argument - (or part of an argument) in a shell command. - - Args: - s: (str) the string to escape - - Returns: - (str) the shell-escaped string - """ - if not s: - # Empty string is a special case: needs to be quoted to ensure that it - # gets treated as a separate argument. - return "''" - for c in s.elems(): - # We do this positively so as to be sure we don't inadvertently forget - # any unsafe characters. - if not c.isalnum() and c not in "@%-_+:,./": - return "'" + s.replace("'", "'\\''") + "'" - return s - -def _detokenize_javacopts(opts): - """Detokenizes a list of options to a depset. - - Args: - opts: ([str]) the javac options to detokenize - - Returns: - (depset[str]) depset of detokenized options - """ - return depset( - [" ".join([_shell_escape(opt) for opt in opts])], - order = "preorder", - ) - -def _derive_output_file(ctx, base_file, *, name_suffix = "", extension = None, extension_suffix = ""): - """Declares a new file whose name is derived from the given file - - This method allows appending a suffix to the name (before extension), changing - the extension or appending a suffix after the extension. The new file is declared - as a sibling of the given base file. At least one of the three options must be - specified. It is an error to specify both `extension` and `extension_suffix`. - - Args: - ctx: (RuleContext) the rule context. - base_file: (File) the file from which to derive the resultant file. - name_suffix: (str) Optional. The suffix to append to the name before the - extension. - extension: (str) Optional. The new extension to use (without '.'). By default, - the base_file's extension is used. - extension_suffix: (str) Optional. The suffix to append to the base_file's extension - - Returns: - (File) the derived file - """ - if not name_suffix and not extension_suffix and not extension: - fail("At least one of name_suffix, extension or extension_suffix is required") - if extension and extension_suffix: - fail("only one of extension or extension_suffix can be specified") - if extension == None: - extension = base_file.extension - new_basename = paths.replace_extension(base_file.basename, name_suffix + "." + extension + extension_suffix) - return ctx.actions.declare_file(new_basename, sibling = base_file) - def _is_stamping_enabled(ctx, stamp): if ctx.configuration.is_tool_configuration(): return 0 @@ -446,39 +241,14 @@ def _is_stamping_enabled(ctx, stamp): # stamp == -1 / auto return int(ctx.configuration.stamp_binaries()) -def _get_relative(path_a, path_b): - if paths.is_absolute(path_b): - return path_b - return paths.normalize(paths.join(path_a, path_b)) - -def _tokenize_javacopts(ctx = None, opts = []): - """Tokenizes a list or depset of options to a list. - - Iff opts is a depset, we reverse the flattened list to ensure right-most - duplicates are preserved in their correct position. - - If the ctx parameter is omitted, a slow, but pure Starlark, implementation - of shell tokenization is used. Otherwise, tokenization is performed using - ctx.tokenize() which has significantly better performance (up to 100x for - large options lists). - - Args: - ctx: (RuleContext|None) the rule context - opts: (depset[str]|[str]) the javac options to tokenize - Returns: - [str] list of tokenized options - """ - if hasattr(opts, "to_list"): - opts = reversed(opts.to_list()) - if ctx: - return [ - token - for opt in opts - for token in ctx.tokenize(opt) - ] +def _get_build_info(ctx, stamp): + if helper.is_stamping_enabled(ctx, stamp): + # Makes the target depend on BUILD_INFO_KEY, which helps to discover stamped targets + # See b/326620485 for more details. + ctx.version_file # buildifier: disable=no-effect + return ctx.attr._build_info_translator[OutputGroupInfo].non_redacted_build_info_files.to_list() else: - # TODO: optimize and use the pure Starlark implementation in cc_helper - return semantics.tokenize_javacopts(opts) + return ctx.attr._build_info_translator[OutputGroupInfo].redacted_build_info_files.to_list() helper = struct( collect_all_targets_as_deps = _collect_all_targets_as_deps, @@ -496,16 +266,15 @@ helper = struct( get_coverage_config = _get_coverage_config, get_java_executable = _get_java_executable, is_absolute_target_platform_path = _is_absolute_target_platform_path, - is_target_platform_windows = _is_target_platform_windows, + is_target_platform_windows = _loading_phase_helper.is_target_platform_windows, runfiles_enabled = _runfiles_enabled, get_test_support = _get_test_support, - test_providers = _test_providers, - executable_providers = _executable_providers, - create_single_jar = _create_single_jar, - shell_escape = _shell_escape, - detokenize_javacopts = _detokenize_javacopts, - tokenize_javacopts = _tokenize_javacopts, - derive_output_file = _derive_output_file, + create_single_jar = _loading_phase_helper.create_single_jar, + shell_escape = _loading_phase_helper.shell_escape, + detokenize_javacopts = _loading_phase_helper.detokenize_javacopts, + tokenize_javacopts = _loading_phase_helper.tokenize_javacopts, is_stamping_enabled = _is_stamping_enabled, - get_relative = _get_relative, + get_build_info = _get_build_info, + get_relative = _loading_phase_helper.get_relative, + has_target_constraints = _loading_phase_helper.has_target_constraints, ) diff --git a/java/common/rules/java_binary.bzl b/java/common/rules/java_binary.bzl index cdd79f29..609ca974 100644 --- a/java/common/rules/java_binary.bzl +++ b/java/common/rules/java_binary.bzl @@ -303,7 +303,7 @@ will be ignored for this target. "classpath_resources": attr.label_list( allow_files = True, doc = """ -DO NOT USE THIS OPTION UNLESS THERE IS NO OTHER WAY) +DO NOT USE THIS OPTION UNLESS THERE IS NO OTHER WAY

A list of resources that must be located at the root of the java tree. This attribute's only purpose is to support third-party libraries that require that their resources be diff --git a/java/common/rules/java_helper.bzl b/java/common/rules/java_helper.bzl new file mode 100644 index 00000000..ee274ade --- /dev/null +++ b/java/common/rules/java_helper.bzl @@ -0,0 +1,212 @@ +# Copyright 2025 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Common util functions for java_* rules""" + +load("@bazel_skylib//lib:paths.bzl", "paths") +load("//java/common:java_semantics.bzl", "semantics") + +# copybara: rules_java visibility + +def _java_segments(path): + if path.startswith("/"): + fail("path must not be absolute: '%s'" % path) + segments = path.split("/") + root_idx = -1 + for idx, segment in enumerate(segments): + if segment in ["java", "javatests", "src", "testsrc"]: + root_idx = idx + break + if root_idx < 0: + return None + is_src = "src" == segments[root_idx] + check_mvn_idx = root_idx if is_src else -1 + if (root_idx == 0 or is_src): + for i in range(root_idx + 1, len(segments) - 1): + segment = segments[i] + if "src" == segment or (is_src and (segment in ["java", "javatests"])): + next = segments[i + 1] + if next in ["com", "org", "net"]: + root_idx = i + elif "src" == segment: + check_mvn_idx = i + break + + if check_mvn_idx >= 0 and check_mvn_idx < len(segments) - 2: + next = segments[check_mvn_idx + 1] + if next in ["main", "test"]: + next = segments[check_mvn_idx + 2] + if next in ["java", "resources"]: + root_idx = check_mvn_idx + 2 + return segments[(root_idx + 1):] + +def _has_target_constraints(ctx, constraints): + # Constraints is a label_list. + for constraint in constraints: + constraint_value = constraint[platform_common.ConstraintValueInfo] + if ctx.target_platform_has_constraint(constraint_value): + return True + return False + +def _is_target_platform_windows(ctx): + return _has_target_constraints(ctx, ctx.attr._windows_constraints) + +def _resource_mapper(file): + root_relative_path = paths.relativize( + path = file.path, + start = paths.join(file.root.path, file.owner.workspace_root), + ) + return "%s:%s" % ( + file.path, + semantics.get_default_resource_path(root_relative_path, segment_extractor = _java_segments), + ) + +def _create_single_jar( + actions, + toolchain, + output, + sources = depset(), + resources = depset(), + mnemonic = "JavaSingleJar", + progress_message = "Building singlejar jar %{output}", + build_target = None, + output_creator = None): + """Register singlejar action for the output jar. + + Args: + actions: (actions) ctx.actions + toolchain: (JavaToolchainInfo) The java toolchain + output: (File) Output file of the action. + sources: (depset[File]) The jar files to merge into the output jar. + resources: (depset[File]) The files to add to the output jar. + mnemonic: (str) The action identifier + progress_message: (str) The action progress message + build_target: (Label) The target label to stamp in the manifest. Optional. + output_creator: (str) The name of the tool to stamp in the manifest. Optional, + defaults to 'singlejar' + Returns: + (File) Output file which was used for registering the action. + """ + args = actions.args() + args.set_param_file_format("shell").use_param_file("@%s", use_always = True) + args.add("--output", output) + args.add_all( + [ + "--compression", + "--normalize", + "--exclude_build_data", + "--warn_duplicate_resources", + ], + ) + args.add_all("--sources", sources) + args.add_all("--resources", resources, map_each = _resource_mapper) + + args.add("--build_target", build_target) + args.add("--output_jar_creator", output_creator) + + actions.run( + mnemonic = mnemonic, + progress_message = progress_message, + executable = toolchain.single_jar, + toolchain = semantics.JAVA_TOOLCHAIN_TYPE, + inputs = depset(transitive = [resources, sources]), + tools = [toolchain.single_jar], + outputs = [output], + arguments = [args], + use_default_shell_env = True, + ) + return output + +# TODO(hvd): use skylib shell.quote() +def _shell_escape(s): + """Shell-escape a string + + Quotes a word so that it can be used, without further quoting, as an argument + (or part of an argument) in a shell command. + + Args: + s: (str) the string to escape + + Returns: + (str) the shell-escaped string + """ + if not s: + # Empty string is a special case: needs to be quoted to ensure that it + # gets treated as a separate argument. + return "''" + for c in s.elems(): + # We do this positively so as to be sure we don't inadvertently forget + # any unsafe characters. + if not c.isalnum() and c not in "@%-_+:,./": + return "'" + s.replace("'", "'\\''") + "'" + return s + +def _detokenize_javacopts(opts): + """Detokenizes a list of options to a depset. + + Args: + opts: ([str]) the javac options to detokenize + + Returns: + (depset[str]) depset of detokenized options + """ + return depset( + [" ".join([_shell_escape(opt) for opt in opts])], + order = "preorder", + ) + +def _get_relative(path_a, path_b): + if paths.is_absolute(path_b): + return path_b + return paths.normalize(paths.join(path_a, path_b)) + +def _tokenize_javacopts(ctx = None, opts = []): + """Tokenizes a list or depset of options to a list. + + Iff opts is a depset, we reverse the flattened list to ensure right-most + duplicates are preserved in their correct position. + + If the ctx parameter is omitted, a slow, but pure Starlark, implementation + of shell tokenization is used. Otherwise, tokenization is performed using + ctx.tokenize() which has significantly better performance (up to 100x for + large options lists). + + Args: + ctx: (RuleContext|None) the rule context + opts: (depset[str]|[str]) the javac options to tokenize + Returns: + [str] list of tokenized options + """ + if hasattr(opts, "to_list"): + opts = reversed(opts.to_list()) + if ctx: + return [ + token + for opt in opts + for token in ctx.tokenize(opt) + ] + else: + # TODO: optimize and use the pure Starlark implementation in cc_helper + return semantics.tokenize_javacopts(opts) + +helper = struct( + is_target_platform_windows = _is_target_platform_windows, + create_single_jar = _create_single_jar, + shell_escape = _shell_escape, + detokenize_javacopts = _detokenize_javacopts, + tokenize_javacopts = _tokenize_javacopts, + get_relative = _get_relative, + has_target_constraints = _has_target_constraints, + java_segments = _java_segments, +) diff --git a/java/common/rules/java_package_configuration.bzl b/java/common/rules/java_package_configuration.bzl index 2c24b450..a1abcd05 100644 --- a/java/common/rules/java_package_configuration.bzl +++ b/java/common/rules/java_package_configuration.bzl @@ -14,11 +14,11 @@ """Implementation for the java_package_configuration rule""" -load("//java/common/rules/impl:java_helper.bzl", "helper") +load("//java/common/rules:java_helper.bzl", "helper") load("//java/private:boot_class_path_info.bzl", "BootClassPathInfo") load("//java/private:native.bzl", "get_internal_java_common") -# copybara: default visibility +# copybara: rules_java visibility JavaPackageConfigurationInfo = provider( "A provider for Java per-package configuration", diff --git a/java/common/rules/java_runtime.bzl b/java/common/rules/java_runtime.bzl index 42321173..2433549c 100644 --- a/java/common/rules/java_runtime.bzl +++ b/java/common/rules/java_runtime.bzl @@ -19,7 +19,7 @@ Definition of java_runtime rule and JavaRuntimeInfo provider. load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load("//java/common:java_semantics.bzl", "semantics") -load("//java/common/rules/impl:java_helper.bzl", "helper") +load("//java/common/rules:java_helper.bzl", "helper") # copybara: default visibility @@ -54,7 +54,7 @@ JavaRuntimeInfo, _new_javaruntimeinfo = provider( ) def _is_main_repo(label): - return label.workspace_name == "" + return label.repo_name == "" def _default_java_home(label): if _is_main_repo(label): @@ -70,7 +70,7 @@ def _get_runfiles_java_executable(ctx, java_home, label): if paths.is_absolute(java_home) or _is_main_repo(label): return helper.get_relative(java_home, _get_bin_java(ctx)) else: - repo_runfiles_path = "" if _is_main_repo(label) else helper.get_relative("..", label.workspace_name) + repo_runfiles_path = "" if _is_main_repo(label) else helper.get_relative("..", label.repo_name) return helper.get_relative(repo_runfiles_path, _get_bin_java(ctx)) def _is_java_binary(path): diff --git a/java/common/rules/java_single_jar.bzl b/java/common/rules/java_single_jar.bzl new file mode 100644 index 00000000..ca768873 --- /dev/null +++ b/java/common/rules/java_single_jar.bzl @@ -0,0 +1,190 @@ +# Copyright 2026 The Bazel Authors. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +"""Definition of the java_single_jar rule.""" + +load("//java/common:java_common.bzl", "java_common") +load("//java/common:java_info.bzl", "JavaInfo") +load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules/impl:java_helper.bzl", "helper") + +# copybara: default visibility + +def _single_jar_inputs(deps, deploy_env): + transitive_inputs = [] + for dep in deps: + if JavaInfo in dep: + info = dep[JavaInfo] + transitive_inputs.append(info.transitive_runtime_jars) + if hasattr(info, "compilation_info"): + compilation_info = info.compilation_info + if hasattr(compilation_info, "runtime_classpath"): + transitive_inputs.append(compilation_info.runtime_classpath) + else: + files = [] + for f in dep[DefaultInfo].files.to_list(): + if not f.extension == "jar": + fail("unexpected file type in java_single_jar.deps: %s" % f.path) + files.append(f) + transitive_inputs.append(depset(files)) + inputs = depset(transitive = transitive_inputs) + + if hasattr(java_common, "JavaRuntimeClasspathInfo"): + deploy_env_jars = depset(transitive = [ + dep[java_common.JavaRuntimeClasspathInfo].runtime_classpath + for dep in deploy_env + ]) + excluded_jars = {jar: None for jar in deploy_env_jars.to_list()} + if excluded_jars: + inputs = depset([jar for jar in inputs.to_list() if jar not in excluded_jars]) + return inputs + +def _bazel_java_single_jar_impl(ctx): + inputs = _single_jar_inputs(ctx.attr.deps, ctx.attr.deploy_env) + + args = ctx.actions.args() + args.add_all("--sources", inputs) + args.use_param_file("@%s") + args.set_param_file_format("multiline") + args.add_all("--deploy_manifest_lines", ctx.attr.deploy_manifest_lines) + args.add("--output", ctx.outputs.output) + args.add("--normalize") + + # Deal with limitation of singlejar flags: tool's default behavior is + # "no", but you get that behavior only by absence of compression flags. + if ctx.attr.compress == "preserve": + args.add("--dont_change_compression") + elif ctx.attr.compress == "yes": + args.add("--compression") + elif ctx.attr.compress == "no": + pass + else: + fail("\"compress\" attribute (%s) must be: yes, no, preserve." % ctx.attr.compress) + + if ctx.attr.exclude_build_data and ctx.attr.stamp == 1: + fail("Enabling stamping has not effect with exclude_build_data enabled") + + build_info_files = [] + if ctx.attr.exclude_build_data: + args.add("--exclude_build_data") + else: + build_info_files = helper.get_build_info(ctx, ctx.attr.stamp) + args.add_all(build_info_files, before_each = "--build_info_file") + if ctx.attr.multi_release: + args.add("--multi_release") + + if ctx.attr.exclude_pattern: + args.add("--exclude_pattern", ctx.attr.exclude_pattern) + + ctx.actions.run( + inputs = depset(build_info_files, transitive = [inputs]), + outputs = [ctx.outputs.output], + arguments = [args], + progress_message = "Merging into %s" % ctx.outputs.output.short_path, + mnemonic = "JavaSingleJar", + executable = ctx.executable._singlejar, + use_default_shell_env = True, + ) + + files = depset([ctx.outputs.output]) + providers = [DefaultInfo( + files = files, + runfiles = ctx.runfiles(transitive_files = files), + )] + if hasattr(java_common, "JavaRuntimeClasspathInfo"): + providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = inputs)) + return providers + +bazel_java_single_jar = rule( + attrs = { + "deps": attr.label_list( + allow_files = True, + doc = """ + The Java targets (including java_import and java_library) to collect + transitive dependencies from. Runtime dependencies are collected via + deps, exports, and runtime_deps. Resources are also collected. + Native cc_library or java_wrap_cc dependencies are not.""", + ), + "deploy_manifest_lines": attr.string_list(doc = """ + A list of lines to add to the META-INF/manifest.mf file."""), + "deploy_env": attr.label_list( + providers = [java_common.JavaRuntimeClasspathInfo] if hasattr(java_common, "JavaRuntimeClasspathInfo") else [], + allow_files = False, + doc = """ + A list of `java_binary` or `java_single_jar` targets which represent + the deployment environment for this binary. + + Set this attribute when building a plugin which will be loaded by another + `java_binary`. + + `deploy_env` dependencies are excluded from the jar built by this rule.""", + ), + "compress": attr.string(default = "preserve", doc = """ + Whether to always deflate ("yes"), always store ("no"), or pass + through unmodified ("preserve"). The default is "preserve", and is the + most efficient option -- no extra work is done to inflate or deflate."""), + "exclude_build_data": attr.bool(default = True, doc = """ + Whether to omit the build-data.properties file generated + by default."""), + "multi_release": attr.bool(default = True, doc = """Whether to enable Multi-Release output jars."""), + "exclude_pattern": attr.string(default = "", doc = """ + A regex pattern of files to exclude from the jar. + """), + "_singlejar": attr.label( + default = Label("//toolchains:singlejar"), + cfg = "exec", + allow_single_file = True, + executable = True, + ), + "output": attr.output(), + "stamp": attr.int( + doc = """ + Whether to embed extra Bazel build information into the build_data.properties file: + * `stamp = 1`: Always embed Bazel build information, even in `--nostamp` builds. + * `stamp = 0`: Embed Bazel build information with constant values, even in `--stamp` builds. + * `stamp = -1`: Embedding of Bazel build information is controlled by the `--[no]stamp` flag. + + Note: whether the output contains the build_data.properties file is controlled + by the `exclude_build_data` attribute. + """, + default = 0, + values = [-1, 0, 1], + ), + "_build_info_translator": attr.label(default = semantics.BUILD_INFO_TRANSLATOR_LABEL), + }, + implementation = _bazel_java_single_jar_impl, + doc = """ +Collects Java dependencies and jar files into a single jar + +`java_single_jar` collects Java dependencies and jar files into a single jar. +This is similar to java_binary with everything related to executables disabled, +and provides an alternative to the java_binary "deploy jar hack". + +## Example + +```skylark +load("//tools/build_defs/java_single_jar:java_single_jar.bzl", "java_single_jar") + +java_single_jar( + name = "my_single_jar", + deps = [ + "//java/com/google/foo", + "//java/com/google/bar", + ], +) +``` + +Outputs: + {name}.jar: A single jar containing all of the inputs. +""", +) diff --git a/java/common/rules/java_toolchain.bzl b/java/common/rules/java_toolchain.bzl index fe32fc36..a24ae4f1 100644 --- a/java/common/rules/java_toolchain.bzl +++ b/java/common/rules/java_toolchain.bzl @@ -17,7 +17,7 @@ Definition of java_toolchain rule and JavaToolchainInfo provider. """ load("//java/common:java_semantics.bzl", "semantics") -load("//java/common/rules/impl:java_helper.bzl", "helper") +load("//java/common/rules:java_helper.bzl", "helper") load("//java/private:boot_class_path_info.bzl", "BootClassPathInfo") load("//java/private:java_info.bzl", "JavaPluginDataInfo") load("//java/private:native.bzl", "get_internal_java_common") @@ -43,7 +43,7 @@ JavaToolchainInfo, _new_javatoolchaininfo = provider( "jvm_opt": "(depset[str]) The default options for the JVM running the java compiler and associated tools.", "label": "(label) The toolchain label.", "proguard_allowlister": "(FilesToRunProvider) The binary to validate proguard configuration.", - "single_jar": "(FilesToRunProvider) The SingleJar deploy jar.", + "single_jar": "(FilesToRunProvider) The SingleJar executable.", "source_version": "(str) The java source version.", "target_version": "(str) The java target version.", "tools": "(depset[File]) The compilation tools.", @@ -240,6 +240,7 @@ def _extract_singleton_list_value(dict, key): else: dict[key] = None +# TODO: b/463873596 - remove this in Bazel 10 _LEGACY_ANY_TYPE_ATTRS = [ "genclass", "deps_checker", @@ -545,7 +546,7 @@ Label of the Proguard allowlister. allow_files = True, executable = True, doc = """ -Label of the SingleJar deploy jar. +Label of the SingleJar executable. """, ), "source_version": attr.string( diff --git a/java/docs/BUILD.bazel b/java/docs/BUILD.bazel deleted file mode 100644 index f2b59360..00000000 --- a/java/docs/BUILD.bazel +++ /dev/null @@ -1,41 +0,0 @@ -load("@bazel_skylib//:bzl_library.bzl", "bzl_library") -load("@stardoc//stardoc:stardoc.bzl", "stardoc") - -package(default_applicable_licenses = ["@rules_java//:license"]) - -exports_files( - ["rules.md"], - visibility = ["//test:__pkg__"], -) - -bzl_library( - name = "rules_bzl", - srcs = ["rules.bzl"], - deps = [ - "//java/bazel/rules", - "//java/common/rules:toolchain_rules", - ], -) - -stardoc( - name = "rules_docs", - out = "rules_docs.out", - input = "rules.bzl", - rule_template = ":rule.vm", - symbol_names = [ - # core rules - "java_binary", - "java_import", - "java_library", - "java_plugin", - "java_test", - - # toolchain rules - "java_package_configuration", - "java_runtime", - "java_toolchain", - ], - table_of_contents_template = "@stardoc//stardoc:templates/markdown_tables/table_of_contents.vm", - visibility = ["//test:__pkg__"], - deps = [":rules_bzl"], -) diff --git a/java/docs/rule.vm b/java/docs/rule.vm deleted file mode 100644 index dd89fdf8..00000000 --- a/java/docs/rule.vm +++ /dev/null @@ -1,20 +0,0 @@ - - -#[[##]]# ${ruleName} - -

-${util.ruleSummary($ruleName, $ruleInfo)}
-
- -${ruleInfo.docString} - -**ATTRIBUTES** - -#if (!$ruleInfo.getAttributeList().isEmpty()) - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -#foreach ($attribute in $ruleInfo.getAttributeList()) -| $attribute.name | #if(!$attribute.docString.isEmpty()) ${util.markdownCellFormat($attribute.docString)} #else - #end | ${util.attributeTypeString($attribute)} | ${util.mandatoryString($attribute)} | #if(!$attribute.defaultValue.isEmpty()) ${util.markdownCodeSpan($attribute.defaultValue)} #end | -#end -#end \ No newline at end of file diff --git a/java/docs/rules.bzl b/java/docs/rules.bzl deleted file mode 100644 index fa6c3dd8..00000000 --- a/java/docs/rules.bzl +++ /dev/null @@ -1,22 +0,0 @@ -"""Java rules""" - -load("//java/bazel/rules:bazel_java_binary.bzl", _java_binary = "java_binary") -load("//java/bazel/rules:bazel_java_import.bzl", _java_import = "java_import") -load("//java/bazel/rules:bazel_java_library.bzl", _java_library = "java_library") -load("//java/bazel/rules:bazel_java_plugin.bzl", _java_plugin = "java_plugin") -load("//java/bazel/rules:bazel_java_test.bzl", _java_test = "java_test") -load("//java/common/rules:java_package_configuration.bzl", _java_package_configuration = "java_package_configuration") -load("//java/common/rules:java_runtime.bzl", _java_runtime = "java_runtime") -load("//java/common/rules:java_toolchain.bzl", _java_toolchain = "java_toolchain") - -visibility("private") - -java_binary = _java_binary -java_import = _java_import -java_library = _java_library -java_plugin = _java_plugin -java_test = _java_test - -java_package_configuration = _java_package_configuration -java_runtime = _java_runtime -java_toolchain = _java_toolchain diff --git a/java/docs/rules.md b/java/docs/rules.md deleted file mode 100644 index b6dd015c..00000000 --- a/java/docs/rules.md +++ /dev/null @@ -1,590 +0,0 @@ - - -Java rules - - -## Rules - -- [java_binary](#java_binary) -- [java_import](#java_import) -- [java_library](#java_library) -- [java_package_configuration](#java_package_configuration) -- [java_plugin](#java_plugin) -- [java_runtime](#java_runtime) -- [java_test](#java_test) -- [java_toolchain](#java_toolchain) - - - - -## java_binary - -
-java_binary(name, deps, srcs, data, resources, add_exports, add_opens, bootclasspath,
-            classpath_resources, create_executable, deploy_env, deploy_manifest_lines, env, javacopts,
-            jvm_flags, launcher, licenses, main_class, neverlink, plugins, resource_strip_prefix,
-            runtime_deps, stamp, use_launcher, use_testrunner)
-
- -

- Builds a Java archive ("jar file"), plus a wrapper shell script with the same name as the rule. - The wrapper shell script uses a classpath that includes, among other things, a jar file for each - library on which the binary depends. When running the wrapper shell script, any nonempty - JAVABIN environment variable will take precedence over the version specified via - Bazel's --java_runtime_version flag. -

-

- The wrapper script accepts several unique flags. Refer to - //src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt - for a list of configurable flags and environment variables accepted by the wrapper. -

- -

Implicit output targets

-
    -
  • name.jar: A Java archive, containing the class files and other - resources corresponding to the binary's direct dependencies.
  • -
  • name-src.jar: An archive containing the sources ("source - jar").
  • -
  • name_deploy.jar: A Java archive suitable for deployment (only - built if explicitly requested). -

    - Building the <name>_deploy.jar target for your rule - creates a self-contained jar file with a manifest that allows it to be run with the - java -jar command or with the wrapper script's --singlejar - option. Using the wrapper script is preferred to java -jar because it - also passes the JVM flags and the options - to load native libraries. -

    -

    - The deploy jar contains all the classes that would be found by a classloader that - searched the classpath from the binary's wrapper script from beginning to end. It also - contains the native libraries needed for dependencies. These are automatically loaded - into the JVM at runtime. -

    -

    If your target specifies a launcher - attribute, then instead of being a normal JAR file, the _deploy.jar will be a - native binary. This will contain the launcher plus any native (C++) dependencies of - your rule, all linked into a static binary. The actual jar file's bytes will be - appended to that native binary, creating a single binary blob containing both the - executable and the Java code. You can execute the resulting jar file directly - like you would execute any native binary.

    -
  • -
  • name_deploy-src.jar: An archive containing the sources - collected from the transitive closure of the target. These will match the classes in the - deploy.jar except where jars have no matching source jar.
  • -
- -

-It is good practice to use the name of the source file that is the main entry point of the -application (minus the extension). For example, if your entry point is called -Main.java, then your name could be Main. -

- -

- A deps attribute is not allowed in a java_binary rule without - srcs; such a rule requires a - main_class provided by - runtime_deps. -

- -

The following code snippet illustrates a common mistake:

- -
-
-java_binary(
-    name = "DontDoThis",
-    srcs = [
-        ...,
-        "GeneratedJavaFile.java",  # a generated .java file
-    ],
-    deps = [":generating_rule",],  # rule that generates that file
-)
-
-
- -

Do this instead:

- -
-
-java_binary(
-    name = "DoThisInstead",
-    srcs = [
-        ...,
-        ":generating_rule",
-    ],
-)
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| deps | The list of other libraries to be linked in to the target. See general comments about deps at Typical attributes defined by most build rules. | List of labels | optional | `[]` | -| srcs | The list of source files that are processed to create the target. This attribute is almost always required; see exceptions below.

Source files of type .java are compiled. In case of generated .java files it is generally advisable to put the generating rule's name here instead of the name of the file itself. This not only improves readability but makes the rule more resilient to future changes: if the generating rule generates different files in the future, you only need to fix one place: the outs of the generating rule. You should not list the generating rule in deps because it is a no-op.

Source files of type .srcjar are unpacked and compiled. (This is useful if you need to generate a set of .java files with a genrule.)

Rules: if the rule (typically genrule or filegroup) generates any of the files listed above, they will be used the same way as described for source files.



This argument is almost always required, except if a main_class attribute specifies a class on the runtime classpath or you specify the runtime_deps argument.

| List of labels | optional | `[]` | -| data | The list of files needed by this library at runtime. See general comments about data at Typical attributes defined by most build rules. | List of labels | optional | `[]` | -| resources | A list of data files to include in a Java jar.

Resources may be source files or generated files.



If resources are specified, they will be bundled in the jar along with the usual .class files produced by compilation. The location of the resources inside of the jar file is determined by the project structure. Bazel first looks for Maven's standard directory layout, (a "src" directory followed by a "resources" directory grandchild). If that is not found, Bazel then looks for the topmost directory named "java" or "javatests" (so, for example, if a resource is at <workspace root>/x/java/y/java/z, the path of the resource will be y/java/z. This heuristic cannot be overridden, however, the resource_strip_prefix attribute can be used to specify a specific alternative directory for resource files. | List of labels | optional | `[]` | -| add_exports | Allow this library to access the given module or package.

This corresponds to the javac and JVM --add-exports= flags. | List of strings | optional | `[]` | -| add_opens | Allow this library to reflectively access the given module or package.

This corresponds to the javac and JVM --add-opens= flags. | List of strings | optional | `[]` | -| bootclasspath | Restricted API, do not use! | Label | optional | `None` | -| classpath_resources | DO NOT USE THIS OPTION UNLESS THERE IS NO OTHER WAY)

A list of resources that must be located at the root of the java tree. This attribute's only purpose is to support third-party libraries that require that their resources be found on the classpath as exactly "myconfig.xml". It is only allowed on binaries and not libraries, due to the danger of namespace conflicts.

| List of labels | optional | `[]` | -| create_executable | Deprecated, use java_single_jar instead. | Boolean | optional | `True` | -| deploy_env | A list of other java_binary targets which represent the deployment environment for this binary. Set this attribute when building a plugin which will be loaded by another java_binary.
Setting this attribute excludes all dependencies from the runtime classpath (and the deploy jar) of this binary that are shared between this binary and the targets specified in deploy_env. | List of labels | optional | `[]` | -| deploy_manifest_lines | A list of lines to add to the META-INF/manifest.mf file generated for the *_deploy.jar target. The contents of this attribute are not subject to "Make variable" substitution. | List of strings | optional | `[]` | -| env | - | Dictionary: String -> String | optional | `{}` | -| javacopts | Extra compiler options for this binary. Subject to "Make variable" substitution and Bourne shell tokenization.

These compiler options are passed to javac after the global compiler options.

| List of strings | optional | `[]` | -| jvm_flags | A list of flags to embed in the wrapper script generated for running this binary. Subject to $(location) and "Make variable" substitution, and Bourne shell tokenization.

The wrapper script for a Java binary includes a CLASSPATH definition (to find all the dependent jars) and invokes the right Java interpreter. The command line generated by the wrapper script includes the name of the main class followed by a "$@" so you can pass along other arguments after the classname. However, arguments intended for parsing by the JVM must be specified before the classname on the command line. The contents of jvm_flags are added to the wrapper script before the classname is listed.



Note that this attribute has no effect on *_deploy.jar outputs.

| List of strings | optional | `[]` | -| launcher | Specify a binary that will be used to run your Java program instead of the normal bin/java program included with the JDK. The target must be a cc_binary. Any cc_binary that implements the Java Invocation API can be specified as a value for this attribute.

By default, Bazel will use the normal JDK launcher (bin/java or java.exe).



The related --java_launcher Bazel flag affects only those java_binary and java_test targets that have not specified a launcher attribute.



Note that your native (C++, SWIG, JNI) dependencies will be built differently depending on whether you are using the JDK launcher or another launcher:



  • If you are using the normal JDK launcher (the default), native dependencies are built as a shared library named {name}_nativedeps.so, where {name} is the name attribute of this java_binary rule. Unused code is not removed by the linker in this configuration.


  • If you are using any other launcher, native (C++) dependencies are statically linked into a binary named {name}_nativedeps, where {name} is the name attribute of this java_binary rule. In this case, the linker will remove any code it thinks is unused from the resulting binary, which means any C++ code accessed only via JNI may not be linked in unless that cc_library target specifies alwayslink = True.


When using any launcher other than the default JDK launcher, the format of the *_deploy.jar output changes. See the main java_binary docs for details.

| Label | optional | `None` | -| licenses | - | List of strings | optional | `[]` | -| main_class | Name of class with main() method to use as entry point. If a rule uses this option, it does not need a srcs=[...] list. Thus, with this attribute one can make an executable from a Java library that already contains one or more main() methods.

The value of this attribute is a class name, not a source file. The class must be available at runtime: it may be compiled by this rule (from srcs) or provided by direct or transitive dependencies (through runtime_deps or deps). If the class is unavailable, the binary will fail at runtime; there is no build-time check.

| String | optional | `""` | -| neverlink | - | Boolean | optional | `False` | -| plugins | Java compiler plugins to run at compile-time. Every java_plugin specified in this attribute will be run whenever this rule is built. A library may also inherit plugins from dependencies that use exported_plugins. Resources generated by the plugin will be included in the resulting jar of this rule. | List of labels | optional | `[]` | -| resource_strip_prefix | The path prefix to strip from Java resources.

If specified, this path prefix is stripped from every file in the resources attribute. It is an error for a resource file not to be under this directory. If not specified (the default), the path of resource file is determined according to the same logic as the Java package of source files. For example, a source file at stuff/java/foo/bar/a.txt will be located at foo/bar/a.txt.

| String | optional | `""` | -| runtime_deps | Libraries to make available to the final binary or test at runtime only. Like ordinary deps, these will appear on the runtime classpath, but unlike them, not on the compile-time classpath. Dependencies needed only at runtime should be listed here. Dependency-analysis tools should ignore targets that appear in both runtime_deps and deps. | List of labels | optional | `[]` | -| stamp | Whether to encode build information into the binary. Possible values:
  • stamp = 1: Always stamp the build information into the binary, even in --nostamp builds. This setting should be avoided, since it potentially kills remote caching for the binary and any downstream actions that depend on it.
  • stamp = 0: Always replace build information by constant values. This gives good build result caching.
  • stamp = -1: Embedding of build information is controlled by the --[no]stamp flag.

Stamped binaries are not rebuilt unless their dependencies change.

| Integer | optional | `-1` | -| use_launcher | Whether the binary should use a custom launcher.

If this attribute is set to false, the launcher attribute and the related --java_launcher flag will be ignored for this target. | Boolean | optional | `True` | -| use_testrunner | Use the test runner (by default com.google.testing.junit.runner.BazelTestRunner) class as the main entry point for a Java program, and provide the test class to the test runner as a value of bazel.test_suite system property.


You can use this to override the default behavior, which is to use test runner for java_test rules, and not use it for java_binary rules. It is unlikely you will want to do this. One use is for AllTest rules that are invoked by another rule (to set up a database before running the tests, for example). The AllTest rule must be declared as a java_binary, but should still use the test runner as its main entry point.

The name of a test runner class can be overridden with main_class attribute. | Boolean | optional | `False` | - - - - -## java_import - -

-java_import(name, deps, data, add_exports, add_opens, constraints, exports, jars, licenses,
-            neverlink, proguard_specs, runtime_deps, srcjar)
-
- -

- This rule allows the use of precompiled .jar files as - libraries for java_library and - java_binary rules. -

- -

Examples

- -
-
-    java_import(
-        name = "maven_model",
-        jars = [
-            "maven_model/maven-aether-provider-3.2.3.jar",
-            "maven_model/maven-model-3.2.3.jar",
-            "maven_model/maven-model-builder-3.2.3.jar",
-        ],
-    )
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| deps | The list of other libraries to be linked in to the target. See java_library.deps. | List of labels | optional | `[]` | -| data | The list of files needed by this rule at runtime. | List of labels | optional | `[]` | -| add_exports | Allow this library to access the given module or package.

This corresponds to the javac and JVM --add-exports= flags. | List of strings | optional | `[]` | -| add_opens | Allow this library to reflectively access the given module or package.

This corresponds to the javac and JVM --add-opens= flags. | List of strings | optional | `[]` | -| constraints | Extra constraints imposed on this rule as a Java library. | List of strings | optional | `[]` | -| exports | Targets to make available to users of this rule. See java_library.exports. | List of labels | optional | `[]` | -| jars | The list of JAR files provided to Java targets that depend on this target. | List of labels | required | | -| licenses | - | List of strings | optional | `[]` | -| neverlink | Only use this library for compilation and not at runtime. Useful if the library will be provided by the runtime environment during execution. Examples of libraries like this are IDE APIs for IDE plug-ins or tools.jar for anything running on a standard JDK. | Boolean | optional | `False` | -| proguard_specs | Files to be used as Proguard specification. These will describe the set of specifications to be used by Proguard. If specified, they will be added to any android_binary target depending on this library.

The files included here must only have idempotent rules, namely -dontnote, -dontwarn, assumenosideeffects, and rules that start with -keep. Other options can only appear in android_binary's proguard_specs, to ensure non-tautological merges. | List of labels | optional | `[]` | -| runtime_deps | Libraries to make available to the final binary or test at runtime only. See java_library.runtime_deps. | List of labels | optional | `[]` | -| srcjar | A JAR file that contains source code for the compiled JAR files. | Label | optional | `None` | - - - - -## java_library - -

-java_library(name, deps, srcs, data, resources, add_exports, add_opens, bootclasspath,
-             exported_plugins, exports, javabuilder_jvm_flags, javacopts, licenses, neverlink,
-             plugins, proguard_specs, resource_strip_prefix, runtime_deps)
-
- -

This rule compiles and links sources into a .jar file.

- -

Implicit outputs

-
    -
  • libname.jar: A Java archive containing the class files.
  • -
  • libname-src.jar: An archive containing the sources ("source - jar").
  • -
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| deps | The list of libraries to link into this library. See general comments about deps at Typical attributes defined by most build rules.

The jars built by java_library rules listed in deps will be on the compile-time classpath of this rule. Furthermore the transitive closure of their deps, runtime_deps and exports will be on the runtime classpath.

By contrast, targets in the data attribute are included in the runfiles but on neither the compile-time nor runtime classpath.

| List of labels | optional | `[]` | -| srcs | The list of source files that are processed to create the target. This attribute is almost always required; see exceptions below.

Source files of type .java are compiled. In case of generated .java files it is generally advisable to put the generating rule's name here instead of the name of the file itself. This not only improves readability but makes the rule more resilient to future changes: if the generating rule generates different files in the future, you only need to fix one place: the outs of the generating rule. You should not list the generating rule in deps because it is a no-op.

Source files of type .srcjar are unpacked and compiled. (This is useful if you need to generate a set of .java files with a genrule.)

Rules: if the rule (typically genrule or filegroup) generates any of the files listed above, they will be used the same way as described for source files.

Source files of type .properties are treated as resources.



All other files are ignored, as long as there is at least one file of a file type described above. Otherwise an error is raised.



This argument is almost always required, except if you specify the runtime_deps argument.

| List of labels | optional | `[]` | -| data | The list of files needed by this library at runtime. See general comments about data at Typical attributes defined by most build rules.

When building a java_library, Bazel doesn't put these files anywhere; if the data files are generated files then Bazel generates them. When building a test that depends on this java_library Bazel copies or links the data files into the runfiles area.

| List of labels | optional | `[]` | -| resources | A list of data files to include in a Java jar.

Resources may be source files or generated files.



If resources are specified, they will be bundled in the jar along with the usual .class files produced by compilation. The location of the resources inside of the jar file is determined by the project structure. Bazel first looks for Maven's standard directory layout, (a "src" directory followed by a "resources" directory grandchild). If that is not found, Bazel then looks for the topmost directory named "java" or "javatests" (so, for example, if a resource is at <workspace root>/x/java/y/java/z, the path of the resource will be y/java/z. This heuristic cannot be overridden, however, the resource_strip_prefix attribute can be used to specify a specific alternative directory for resource files. | List of labels | optional | `[]` | -| add_exports | Allow this library to access the given module or package.

This corresponds to the javac and JVM --add-exports= flags. | List of strings | optional | `[]` | -| add_opens | Allow this library to reflectively access the given module or package.

This corresponds to the javac and JVM --add-opens= flags. | List of strings | optional | `[]` | -| bootclasspath | Restricted API, do not use! | Label | optional | `None` | -| exported_plugins | The list of java_plugins (e.g. annotation processors) to export to libraries that directly depend on this library.

The specified list of java_plugins will be applied to any library which directly depends on this library, just as if that library had explicitly declared these labels in plugins.

| List of labels | optional | `[]` | -| exports | Exported libraries.

Listing rules here will make them available to parent rules, as if the parents explicitly depended on these rules. This is not true for regular (non-exported) deps.

Summary: a rule X can access the code in Y if there exists a dependency path between them that begins with a deps edge followed by zero or more exports edges. Let's see some examples to illustrate this.

Assume A depends on B and B depends on C. In this case C is a transitive dependency of A, so changing C's sources and rebuilding A will correctly rebuild everything. However A will not be able to use classes in C. To allow that, either A has to declare C in its deps, or B can make it easier for A (and anything that may depend on A) by declaring C in its (B's) exports attribute.

The closure of exported libraries is available to all direct parent rules. Take a slightly different example: A depends on B, B depends on C and D, and also exports C but not D. Now A has access to C but not to D. Now, if C and D exported some libraries, C' and D' respectively, A could only access C' but not D'.

Important: an exported rule is not a regular dependency. Sticking to the previous example, if B exports C and wants to also use C, it has to also list it in its own deps.

| List of labels | optional | `[]` | -| javabuilder_jvm_flags | Restricted API, do not use! | List of strings | optional | `[]` | -| javacopts | Extra compiler options for this library. Subject to "Make variable" substitution and Bourne shell tokenization.

These compiler options are passed to javac after the global compiler options.

| List of strings | optional | `[]` | -| licenses | - | List of strings | optional | `[]` | -| neverlink | Whether this library should only be used for compilation and not at runtime. Useful if the library will be provided by the runtime environment during execution. Examples of such libraries are the IDE APIs for IDE plug-ins or tools.jar for anything running on a standard JDK.

Note that neverlink = True does not prevent the compiler from inlining material from this library into compilation targets that depend on it, as permitted by the Java Language Specification (e.g., static final constants of String or of primitive types). The preferred use case is therefore when the runtime library is identical to the compilation library.

If the runtime library differs from the compilation library then you must ensure that it differs only in places that the JLS forbids compilers to inline (and that must hold for all future versions of the JLS).

| Boolean | optional | `False` | -| plugins | Java compiler plugins to run at compile-time. Every java_plugin specified in this attribute will be run whenever this rule is built. A library may also inherit plugins from dependencies that use exported_plugins. Resources generated by the plugin will be included in the resulting jar of this rule. | List of labels | optional | `[]` | -| proguard_specs | Files to be used as Proguard specification. These will describe the set of specifications to be used by Proguard. If specified, they will be added to any android_binary target depending on this library.

The files included here must only have idempotent rules, namely -dontnote, -dontwarn, assumenosideeffects, and rules that start with -keep. Other options can only appear in android_binary's proguard_specs, to ensure non-tautological merges. | List of labels | optional | `[]` | -| resource_strip_prefix | The path prefix to strip from Java resources.

If specified, this path prefix is stripped from every file in the resources attribute. It is an error for a resource file not to be under this directory. If not specified (the default), the path of resource file is determined according to the same logic as the Java package of source files. For example, a source file at stuff/java/foo/bar/a.txt will be located at foo/bar/a.txt.

| String | optional | `""` | -| runtime_deps | Libraries to make available to the final binary or test at runtime only. Like ordinary deps, these will appear on the runtime classpath, but unlike them, not on the compile-time classpath. Dependencies needed only at runtime should be listed here. Dependency-analysis tools should ignore targets that appear in both runtime_deps and deps. | List of labels | optional | `[]` | - - - - -## java_package_configuration - -
-java_package_configuration(name, data, javacopts, output_licenses, packages, system)
-
- -

-Configuration to apply to a set of packages. -Configurations can be added to -java_toolchain.javacoptss. -

- -

Example:

- -
-
-
-java_package_configuration(
-    name = "my_configuration",
-    packages = [":my_packages"],
-    javacopts = ["-Werror"],
-)
-
-package_group(
-    name = "my_packages",
-    packages = [
-        "//com/my/project/...",
-        "-//com/my/project/testing/...",
-    ],
-)
-
-java_toolchain(
-    ...,
-    package_configuration = [
-        ":my_configuration",
-    ]
-)
-
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| data | The list of files needed by this configuration at runtime. | List of labels | optional | `[]` | -| javacopts | Java compiler flags. | List of strings | optional | `[]` | -| output_licenses | - | List of strings | optional | `[]` | -| packages | The set of package_groups the configuration should be applied to. | List of labels | optional | `[]` | -| system | Corresponds to javac's --system flag. | Label | optional | `None` | - - - - -## java_plugin - -
-java_plugin(name, deps, srcs, data, resources, add_exports, add_opens, bootclasspath, generates_api,
-            javabuilder_jvm_flags, javacopts, licenses, neverlink, output_licenses, plugins,
-            processor_class, proguard_specs, resource_strip_prefix)
-
- -

- java_plugin defines plugins for the Java compiler run by Bazel. The - only supported kind of plugins are annotation processors. A java_library or - java_binary rule can run plugins by depending on them via the plugins - attribute. A java_library can also automatically export plugins to libraries that - directly depend on it using - exported_plugins. -

- -

Implicit output targets

-
    -
  • libname.jar: A Java archive.
  • -
- -

- Arguments are identical to java_library, except - for the addition of the processor_class argument. -

- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| deps | The list of libraries to link into this library. See general comments about deps at Typical attributes defined by most build rules.

The jars built by java_library rules listed in deps will be on the compile-time classpath of this rule. Furthermore the transitive closure of their deps, runtime_deps and exports will be on the runtime classpath.

By contrast, targets in the data attribute are included in the runfiles but on neither the compile-time nor runtime classpath.

| List of labels | optional | `[]` | -| srcs | The list of source files that are processed to create the target. This attribute is almost always required; see exceptions below.

Source files of type .java are compiled. In case of generated .java files it is generally advisable to put the generating rule's name here instead of the name of the file itself. This not only improves readability but makes the rule more resilient to future changes: if the generating rule generates different files in the future, you only need to fix one place: the outs of the generating rule. You should not list the generating rule in deps because it is a no-op.

Source files of type .srcjar are unpacked and compiled. (This is useful if you need to generate a set of .java files with a genrule.)

Rules: if the rule (typically genrule or filegroup) generates any of the files listed above, they will be used the same way as described for source files.

Source files of type .properties are treated as resources.



All other files are ignored, as long as there is at least one file of a file type described above. Otherwise an error is raised.



This argument is almost always required, except if you specify the runtime_deps argument.

| List of labels | optional | `[]` | -| data | The list of files needed by this library at runtime. See general comments about data at Typical attributes defined by most build rules.

When building a java_library, Bazel doesn't put these files anywhere; if the data files are generated files then Bazel generates them. When building a test that depends on this java_library Bazel copies or links the data files into the runfiles area.

| List of labels | optional | `[]` | -| resources | A list of data files to include in a Java jar.

Resources may be source files or generated files.



If resources are specified, they will be bundled in the jar along with the usual .class files produced by compilation. The location of the resources inside of the jar file is determined by the project structure. Bazel first looks for Maven's standard directory layout, (a "src" directory followed by a "resources" directory grandchild). If that is not found, Bazel then looks for the topmost directory named "java" or "javatests" (so, for example, if a resource is at <workspace root>/x/java/y/java/z, the path of the resource will be y/java/z. This heuristic cannot be overridden, however, the resource_strip_prefix attribute can be used to specify a specific alternative directory for resource files. | List of labels | optional | `[]` | -| add_exports | Allow this library to access the given module or package.

This corresponds to the javac and JVM --add-exports= flags. | List of strings | optional | `[]` | -| add_opens | Allow this library to reflectively access the given module or package.

This corresponds to the javac and JVM --add-opens= flags. | List of strings | optional | `[]` | -| bootclasspath | Restricted API, do not use! | Label | optional | `None` | -| generates_api | This attribute marks annotation processors that generate API code.

If a rule uses an API-generating annotation processor, other rules depending on it can refer to the generated code only if their compilation actions are scheduled after the generating rule. This attribute instructs Bazel to introduce scheduling constraints when --java_header_compilation is enabled.

WARNING: This attribute affects build performance, use it only if necessary.

| Boolean | optional | `False` | -| javabuilder_jvm_flags | Restricted API, do not use! | List of strings | optional | `[]` | -| javacopts | Extra compiler options for this library. Subject to "Make variable" substitution and Bourne shell tokenization.

These compiler options are passed to javac after the global compiler options.

| List of strings | optional | `[]` | -| licenses | - | List of strings | optional | `[]` | -| neverlink | Whether this library should only be used for compilation and not at runtime. Useful if the library will be provided by the runtime environment during execution. Examples of such libraries are the IDE APIs for IDE plug-ins or tools.jar for anything running on a standard JDK.

Note that neverlink = True does not prevent the compiler from inlining material from this library into compilation targets that depend on it, as permitted by the Java Language Specification (e.g., static final constants of String or of primitive types). The preferred use case is therefore when the runtime library is identical to the compilation library.

If the runtime library differs from the compilation library then you must ensure that it differs only in places that the JLS forbids compilers to inline (and that must hold for all future versions of the JLS).

| Boolean | optional | `False` | -| output_licenses | - | List of strings | optional | `[]` | -| plugins | Java compiler plugins to run at compile-time. Every java_plugin specified in this attribute will be run whenever this rule is built. A library may also inherit plugins from dependencies that use exported_plugins. Resources generated by the plugin will be included in the resulting jar of this rule. | List of labels | optional | `[]` | -| processor_class | The processor class is the fully qualified type of the class that the Java compiler should use as entry point to the annotation processor. If not specified, this rule will not contribute an annotation processor to the Java compiler's annotation processing, but its runtime classpath will still be included on the compiler's annotation processor path. (This is primarily intended for use by Error Prone plugins, which are loaded from the annotation processor path using java.util.ServiceLoader.) | String | optional | `""` | -| proguard_specs | Files to be used as Proguard specification. These will describe the set of specifications to be used by Proguard. If specified, they will be added to any android_binary target depending on this library.

The files included here must only have idempotent rules, namely -dontnote, -dontwarn, assumenosideeffects, and rules that start with -keep. Other options can only appear in android_binary's proguard_specs, to ensure non-tautological merges. | List of labels | optional | `[]` | -| resource_strip_prefix | The path prefix to strip from Java resources.

If specified, this path prefix is stripped from every file in the resources attribute. It is an error for a resource file not to be under this directory. If not specified (the default), the path of resource file is determined according to the same logic as the Java package of source files. For example, a source file at stuff/java/foo/bar/a.txt will be located at foo/bar/a.txt.

| String | optional | `""` | - - - - -## java_runtime - -
-java_runtime(name, srcs, default_cds, hermetic_srcs, hermetic_static_libs, java, java_home,
-             lib_ct_sym, lib_modules, output_licenses, version)
-
- -

-Specifies the configuration for a Java runtime. -

- -

Example:

- -
-
-
-java_runtime(
-    name = "jdk-9-ea+153",
-    srcs = glob(["jdk9-ea+153/**"]),
-    java_home = "jdk9-ea+153",
-)
-
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| srcs | All files in the runtime. | List of labels | optional | `[]` | -| default_cds | Default CDS archive for hermetic java_runtime. When hermetic is enabled for a java_binary target and if the target does not provide its own CDS archive by specifying the classlist attribute, the java_runtime default CDS is packaged in the hermetic deploy JAR. | Label | optional | `None` | -| hermetic_srcs | Files in the runtime needed for hermetic deployments. | List of labels | optional | `[]` | -| hermetic_static_libs | The libraries that are statically linked with the launcher for hermetic deployments | List of labels | optional | `[]` | -| java | The path to the java executable. | Label | optional | `None` | -| java_home | The path to the root of the runtime. Subject to "Make" variable substitution. If this path is absolute, the rule denotes a non-hermetic Java runtime with a well-known path. In that case, the srcs and java attributes must be empty. | String | optional | `""` | -| lib_ct_sym | The lib/ct.sym file needed for compilation with --release. If not specified and there is exactly one file in srcs whose path ends with /lib/ct.sym, that file is used. | Label | optional | `None` | -| lib_modules | The lib/modules file needed for hermetic deployments. | Label | optional | `None` | -| output_licenses | - | List of strings | optional | `[]` | -| version | The feature version of the Java runtime. I.e., the integer returned by Runtime.version().feature(). | Integer | optional | `0` | - - - - -## java_test - -
-java_test(name, deps, srcs, data, resources, add_exports, add_opens, bootclasspath,
-          classpath_resources, create_executable, deploy_manifest_lines, env, env_inherit, javacopts,
-          jvm_flags, launcher, licenses, main_class, neverlink, plugins, resource_strip_prefix,
-          runtime_deps, stamp, test_class, use_launcher, use_testrunner)
-
- -

-A java_test() rule compiles a Java test. A test is a binary wrapper around your -test code. The test runner's main method is invoked instead of the main class being compiled. -

- -

Implicit output targets

-
    -
  • name.jar: A Java archive.
  • -
  • name_deploy.jar: A Java archive suitable - for deployment. (Only built if explicitly requested.) See the description of the - name_deploy.jar output from - java_binary for more details.
  • -
- -

-See the section on java_binary() arguments. This rule also -supports all attributes common -to all test rules (*_test). -

- -

Examples

- -
-
-
-java_library(
-    name = "tests",
-    srcs = glob(["*.java"]),
-    deps = [
-        "//java/com/foo/base:testResources",
-        "//java/com/foo/testing/util",
-    ],
-)
-
-java_test(
-    name = "AllTests",
-    size = "small",
-    runtime_deps = [
-        ":tests",
-        "//util/mysql",
-    ],
-)
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| deps | The list of other libraries to be linked in to the target. See general comments about deps at Typical attributes defined by most build rules. | List of labels | optional | `[]` | -| srcs | The list of source files that are processed to create the target. This attribute is almost always required; see exceptions below.

Source files of type .java are compiled. In case of generated .java files it is generally advisable to put the generating rule's name here instead of the name of the file itself. This not only improves readability but makes the rule more resilient to future changes: if the generating rule generates different files in the future, you only need to fix one place: the outs of the generating rule. You should not list the generating rule in deps because it is a no-op.

Source files of type .srcjar are unpacked and compiled. (This is useful if you need to generate a set of .java files with a genrule.)

Rules: if the rule (typically genrule or filegroup) generates any of the files listed above, they will be used the same way as described for source files.



This argument is almost always required, except if a main_class attribute specifies a class on the runtime classpath or you specify the runtime_deps argument.

| List of labels | optional | `[]` | -| data | The list of files needed by this library at runtime. See general comments about data at Typical attributes defined by most build rules. | List of labels | optional | `[]` | -| resources | A list of data files to include in a Java jar.

Resources may be source files or generated files.



If resources are specified, they will be bundled in the jar along with the usual .class files produced by compilation. The location of the resources inside of the jar file is determined by the project structure. Bazel first looks for Maven's standard directory layout, (a "src" directory followed by a "resources" directory grandchild). If that is not found, Bazel then looks for the topmost directory named "java" or "javatests" (so, for example, if a resource is at <workspace root>/x/java/y/java/z, the path of the resource will be y/java/z. This heuristic cannot be overridden, however, the resource_strip_prefix attribute can be used to specify a specific alternative directory for resource files. | List of labels | optional | `[]` | -| add_exports | Allow this library to access the given module or package.

This corresponds to the javac and JVM --add-exports= flags. | List of strings | optional | `[]` | -| add_opens | Allow this library to reflectively access the given module or package.

This corresponds to the javac and JVM --add-opens= flags. | List of strings | optional | `[]` | -| bootclasspath | Restricted API, do not use! | Label | optional | `None` | -| classpath_resources | DO NOT USE THIS OPTION UNLESS THERE IS NO OTHER WAY)

A list of resources that must be located at the root of the java tree. This attribute's only purpose is to support third-party libraries that require that their resources be found on the classpath as exactly "myconfig.xml". It is only allowed on binaries and not libraries, due to the danger of namespace conflicts.

| List of labels | optional | `[]` | -| create_executable | Deprecated, use java_single_jar instead. | Boolean | optional | `True` | -| deploy_manifest_lines | A list of lines to add to the META-INF/manifest.mf file generated for the *_deploy.jar target. The contents of this attribute are not subject to "Make variable" substitution. | List of strings | optional | `[]` | -| env | - | Dictionary: String -> String | optional | `{}` | -| env_inherit | - | List of strings | optional | `[]` | -| javacopts | Extra compiler options for this binary. Subject to "Make variable" substitution and Bourne shell tokenization.

These compiler options are passed to javac after the global compiler options.

| List of strings | optional | `[]` | -| jvm_flags | A list of flags to embed in the wrapper script generated for running this binary. Subject to $(location) and "Make variable" substitution, and Bourne shell tokenization.

The wrapper script for a Java binary includes a CLASSPATH definition (to find all the dependent jars) and invokes the right Java interpreter. The command line generated by the wrapper script includes the name of the main class followed by a "$@" so you can pass along other arguments after the classname. However, arguments intended for parsing by the JVM must be specified before the classname on the command line. The contents of jvm_flags are added to the wrapper script before the classname is listed.



Note that this attribute has no effect on *_deploy.jar outputs.

| List of strings | optional | `[]` | -| launcher | Specify a binary that will be used to run your Java program instead of the normal bin/java program included with the JDK. The target must be a cc_binary. Any cc_binary that implements the Java Invocation API can be specified as a value for this attribute.

By default, Bazel will use the normal JDK launcher (bin/java or java.exe).



The related --java_launcher Bazel flag affects only those java_binary and java_test targets that have not specified a launcher attribute.



Note that your native (C++, SWIG, JNI) dependencies will be built differently depending on whether you are using the JDK launcher or another launcher:



  • If you are using the normal JDK launcher (the default), native dependencies are built as a shared library named {name}_nativedeps.so, where {name} is the name attribute of this java_binary rule. Unused code is not removed by the linker in this configuration.


  • If you are using any other launcher, native (C++) dependencies are statically linked into a binary named {name}_nativedeps, where {name} is the name attribute of this java_binary rule. In this case, the linker will remove any code it thinks is unused from the resulting binary, which means any C++ code accessed only via JNI may not be linked in unless that cc_library target specifies alwayslink = True.


When using any launcher other than the default JDK launcher, the format of the *_deploy.jar output changes. See the main java_binary docs for details.

| Label | optional | `None` | -| licenses | - | List of strings | optional | `[]` | -| main_class | Name of class with main() method to use as entry point. If a rule uses this option, it does not need a srcs=[...] list. Thus, with this attribute one can make an executable from a Java library that already contains one or more main() methods.

The value of this attribute is a class name, not a source file. The class must be available at runtime: it may be compiled by this rule (from srcs) or provided by direct or transitive dependencies (through runtime_deps or deps). If the class is unavailable, the binary will fail at runtime; there is no build-time check.

| String | optional | `""` | -| neverlink | - | Boolean | optional | `False` | -| plugins | Java compiler plugins to run at compile-time. Every java_plugin specified in this attribute will be run whenever this rule is built. A library may also inherit plugins from dependencies that use exported_plugins. Resources generated by the plugin will be included in the resulting jar of this rule. | List of labels | optional | `[]` | -| resource_strip_prefix | The path prefix to strip from Java resources.

If specified, this path prefix is stripped from every file in the resources attribute. It is an error for a resource file not to be under this directory. If not specified (the default), the path of resource file is determined according to the same logic as the Java package of source files. For example, a source file at stuff/java/foo/bar/a.txt will be located at foo/bar/a.txt.

| String | optional | `""` | -| runtime_deps | Libraries to make available to the final binary or test at runtime only. Like ordinary deps, these will appear on the runtime classpath, but unlike them, not on the compile-time classpath. Dependencies needed only at runtime should be listed here. Dependency-analysis tools should ignore targets that appear in both runtime_deps and deps. | List of labels | optional | `[]` | -| stamp | Whether to encode build information into the binary. Possible values:
  • stamp = 1: Always stamp the build information into the binary, even in --nostamp builds. This setting should be avoided, since it potentially kills remote caching for the binary and any downstream actions that depend on it.
  • stamp = 0: Always replace build information by constant values. This gives good build result caching.
  • stamp = -1: Embedding of build information is controlled by the --[no]stamp flag.

Stamped binaries are not rebuilt unless their dependencies change.

| Integer | optional | `0` | -| test_class | The Java class to be loaded by the test runner.

By default, if this argument is not defined then the legacy mode is used and the test arguments are used instead. Set the --nolegacy_bazel_java_test flag to not fallback on the first argument.

This attribute specifies the name of a Java class to be run by this test. It is rare to need to set this. If this argument is omitted, it will be inferred using the target's name and its source-root-relative path. If the test is located outside a known source root, Bazel will report an error if test_class is unset.

For JUnit3, the test class needs to either be a subclass of junit.framework.TestCase or it needs to have a public static suite() method that returns a junit.framework.Test (or a subclass of Test). For JUnit4, the class needs to be annotated with org.junit.runner.RunWith.

This attribute allows several java_test rules to share the same Test (TestCase, TestSuite, ...). Typically additional information is passed to it (e.g. via jvm_flags=['-Dkey=value']) so that its behavior differs in each case, such as running a different subset of the tests. This attribute also enables the use of Java tests outside the javatests tree.

| String | optional | `""` | -| use_launcher | Whether the binary should use a custom launcher.

If this attribute is set to false, the launcher attribute and the related --java_launcher flag will be ignored for this target. | Boolean | optional | `True` | -| use_testrunner | Use the test runner (by default com.google.testing.junit.runner.BazelTestRunner) class as the main entry point for a Java program, and provide the test class to the test runner as a value of bazel.test_suite system property.


You can use this to override the default behavior, which is to use test runner for java_test rules, and not use it for java_binary rules. It is unlikely you will want to do this. One use is for AllTest rules that are invoked by another rule (to set up a database before running the tests, for example). The AllTest rule must be declared as a java_binary, but should still use the test runner as its main entry point.

The name of a test runner class can be overridden with main_class attribute. | Boolean | optional | `True` | - - - - -## java_toolchain - -

-java_toolchain(name, android_lint_data, android_lint_jvm_opts, android_lint_opts,
-               android_lint_package_configuration, android_lint_runner, bootclasspath,
-               compatible_javacopts, deps_checker, forcibly_disable_header_compilation, genclass,
-               header_compiler, header_compiler_builtin_processors, header_compiler_direct, ijar,
-               jacocorunner, java_runtime, javabuilder, javabuilder_data, javabuilder_jvm_opts,
-               javac_supports_multiplex_workers, javac_supports_worker_cancellation,
-               javac_supports_worker_multiplex_sandboxing, javac_supports_workers, javacopts,
-               jspecify_implicit_deps, jspecify_javacopts, jspecify_packages, jspecify_processor,
-               jspecify_processor_class, jspecify_stubs, jvm_opts, licenses, misc, oneversion,
-               oneversion_allowlist, oneversion_allowlist_for_tests, oneversion_whitelist,
-               package_configuration, proguard_allowlister, reduced_classpath_incompatible_processors,
-               singlejar, source_version, target_version, timezone_data, tools, turbine_data,
-               turbine_jvm_opts, xlint)
-
- -

-Specifies the configuration for the Java compiler. Which toolchain to be used can be changed through -the --java_toolchain argument. Normally you should not write those kind of rules unless you want to -tune your Java compiler. -

- -

Examples

- -

A simple example would be: -

- -
-
-
-java_toolchain(
-    name = "toolchain",
-    source_version = "7",
-    target_version = "7",
-    bootclasspath = ["//tools/jdk:bootclasspath"],
-    xlint = [ "classfile", "divzero", "empty", "options", "path" ],
-    javacopts = [ "-g" ],
-    javabuilder = ":JavaBuilder_deploy.jar",
-)
-
-
- -**ATTRIBUTES** - - -| Name | Description | Type | Mandatory | Default | -| :------------- | :------------- | :------------- | :------------- | :------------- | -| name | A unique name for this target. | Name | required | | -| android_lint_data | Labels of tools available for label-expansion in android_lint_jvm_opts. | List of labels | optional | `[]` | -| android_lint_jvm_opts | The list of arguments for the JVM when invoking Android Lint. | List of strings | optional | `[]` | -| android_lint_opts | The list of Android Lint arguments. | List of strings | optional | `[]` | -| android_lint_package_configuration | Android Lint Configuration that should be applied to the specified package groups. | List of labels | optional | `[]` | -| android_lint_runner | Label of the Android Lint runner, if any. | Label | optional | `None` | -| bootclasspath | The Java target bootclasspath entries. Corresponds to javac's -bootclasspath flag. | List of labels | optional | `[]` | -| compatible_javacopts | Internal API, do not use! | Dictionary: String -> List of strings | optional | `{}` | -| deps_checker | Label of the ImportDepsChecker deploy jar. | Label | optional | `None` | -| forcibly_disable_header_compilation | Overrides --java_header_compilation to disable header compilation on platforms that do not support it, e.g. JDK 7 Bazel. | Boolean | optional | `False` | -| genclass | Label of the GenClass deploy jar. | Label | optional | `None` | -| header_compiler | Label of the header compiler. Required if --java_header_compilation is enabled. | Label | optional | `None` | -| header_compiler_builtin_processors | Internal API, do not use! | List of strings | optional | `[]` | -| header_compiler_direct | Optional label of the header compiler to use for direct classpath actions that do not include any API-generating annotation processors.

This tool does not support annotation processing. | Label | optional | `None` | -| ijar | Label of the ijar executable. | Label | optional | `None` | -| jacocorunner | Label of the JacocoCoverageRunner deploy jar. | Label | optional | `None` | -| java_runtime | The java_runtime to use with this toolchain. It defaults to java_runtime in execution configuration. | Label | optional | `None` | -| javabuilder | Label of the JavaBuilder deploy jar. | Label | optional | `None` | -| javabuilder_data | Labels of data available for label-expansion in javabuilder_jvm_opts. | List of labels | optional | `[]` | -| javabuilder_jvm_opts | The list of arguments for the JVM when invoking JavaBuilder. | List of strings | optional | `[]` | -| javac_supports_multiplex_workers | True if JavaBuilder supports running as a multiplex persistent worker, false if it doesn't. | Boolean | optional | `True` | -| javac_supports_worker_cancellation | True if JavaBuilder supports cancellation of persistent workers, false if it doesn't. | Boolean | optional | `True` | -| javac_supports_worker_multiplex_sandboxing | True if JavaBuilder supports running as a multiplex persistent worker with sandboxing, false if it doesn't. | Boolean | optional | `False` | -| javac_supports_workers | True if JavaBuilder supports running as a persistent worker, false if it doesn't. | Boolean | optional | `True` | -| javacopts | The list of extra arguments for the Java compiler. Please refer to the Java compiler documentation for the extensive list of possible Java compiler flags. | List of strings | optional | `[]` | -| jspecify_implicit_deps | Experimental, do not use! | Label | optional | `None` | -| jspecify_javacopts | Experimental, do not use! | List of strings | optional | `[]` | -| jspecify_packages | Experimental, do not use! | List of labels | optional | `[]` | -| jspecify_processor | Experimental, do not use! | Label | optional | `None` | -| jspecify_processor_class | Experimental, do not use! | String | optional | `""` | -| jspecify_stubs | Experimental, do not use! | List of labels | optional | `[]` | -| jvm_opts | The list of arguments for the JVM when invoking the Java compiler. Please refer to the Java virtual machine documentation for the extensive list of possible flags for this option. | List of strings | optional | `[]` | -| licenses | - | List of strings | optional | `[]` | -| misc | Deprecated: use javacopts instead | List of strings | optional | `[]` | -| oneversion | Label of the one-version enforcement binary. | Label | optional | `None` | -| oneversion_allowlist | Label of the one-version allowlist. | Label | optional | `None` | -| oneversion_allowlist_for_tests | Label of the one-version allowlist for tests. | Label | optional | `None` | -| oneversion_whitelist | Deprecated: use oneversion_allowlist instead | Label | optional | `None` | -| package_configuration | Configuration that should be applied to the specified package groups. | List of labels | optional | `[]` | -| proguard_allowlister | Label of the Proguard allowlister. | Label | optional | `"@bazel_tools//tools/jdk:proguard_whitelister"` | -| reduced_classpath_incompatible_processors | Internal API, do not use! | List of strings | optional | `[]` | -| singlejar | Label of the SingleJar deploy jar. | Label | optional | `None` | -| source_version | The Java source version (e.g., '6' or '7'). It specifies which set of code structures are allowed in the Java source code. | String | optional | `""` | -| target_version | The Java target version (e.g., '6' or '7'). It specifies for which Java runtime the class should be build. | String | optional | `""` | -| timezone_data | Label of a resource jar containing timezone data. If set, the timezone data is added as an implicitly runtime dependency of all java_binary rules. | Label | optional | `None` | -| tools | Labels of tools available for label-expansion in jvm_opts. | List of labels | optional | `[]` | -| turbine_data | Labels of data available for label-expansion in turbine_jvm_opts. | List of labels | optional | `[]` | -| turbine_jvm_opts | The list of arguments for the JVM when invoking turbine. | List of strings | optional | `[]` | -| xlint | The list of warning to add or removes from default list. Precedes it with a dash to removes it. Please see the Javac documentation on the -Xlint options for more information. | List of strings | optional | `[]` | - - diff --git a/java/extensions.bzl b/java/extensions.bzl index f456f3f5..a791d179 100644 --- a/java/extensions.bzl +++ b/java/extensions.bzl @@ -21,8 +21,10 @@ load( "remote_jdk11_repos", "remote_jdk17_repos", "remote_jdk21_repos", + "remote_jdk25_repos", "remote_jdk8_repos", ) +load("//toolchains:extensions.bzl", _java_repository = "java_repository") def _toolchains_impl(module_ctx): java_tools_repos() @@ -31,6 +33,7 @@ def _toolchains_impl(module_ctx): remote_jdk11_repos() remote_jdk17_repos() remote_jdk21_repos() + remote_jdk25_repos() if bazel_features.external_deps.extension_metadata_has_reproducible: return module_ctx.extension_metadata(reproducible = True) @@ -38,3 +41,5 @@ def _toolchains_impl(module_ctx): return None toolchains = module_extension(_toolchains_impl) + +java_repository = _java_repository diff --git a/java/java_single_jar.bzl b/java/java_single_jar.bzl index 48aa45c3..84771614 100644 --- a/java/java_single_jar.bzl +++ b/java/java_single_jar.bzl @@ -1,148 +1,5 @@ -""" Definition of _java_single_jar. """ +"""The java_single_jar rule""" -load("//java/common:java_common.bzl", "java_common") -load("//java/common:java_info.bzl", "JavaInfo") +load("//java/bazel/rules:bazel_java_single_jar.bzl", _java_single_jar = "java_single_jar") -def _single_jar_inputs(deps, deploy_env): - transitive_inputs = [] - for dep in deps: - if JavaInfo in dep: - info = dep[JavaInfo] - transitive_inputs.append(info.transitive_runtime_jars) - if hasattr(info, "compilation_info"): - compilation_info = info.compilation_info - if hasattr(compilation_info, "runtime_classpath"): - transitive_inputs.append(compilation_info.runtime_classpath) - else: - files = [] - for f in dep[DefaultInfo].files.to_list(): - if not f.extension == "jar": - fail("unexpected file type in java_single_jar.deps: %s" % f.path) - files.append(f) - transitive_inputs.append(depset(files)) - inputs = depset(transitive = transitive_inputs) - - if hasattr(java_common, "JavaRuntimeClasspathInfo"): - deploy_env_jars = depset(transitive = [ - dep[java_common.JavaRuntimeClasspathInfo].runtime_classpath - for dep in deploy_env - ]) - excluded_jars = {jar: None for jar in deploy_env_jars.to_list()} - if excluded_jars: - inputs = depset([jar for jar in inputs.to_list() if jar not in excluded_jars]) - return inputs - -def _java_single_jar(ctx): - inputs = _single_jar_inputs(ctx.attr.deps, ctx.attr.deploy_env) - - args = ctx.actions.args() - args.add_all("--sources", inputs) - args.use_param_file("@%s") - args.set_param_file_format("multiline") - args.add_all("--deploy_manifest_lines", ctx.attr.deploy_manifest_lines) - args.add("--output", ctx.outputs.jar) - args.add("--normalize") - - # Deal with limitation of singlejar flags: tool's default behavior is - # "no", but you get that behavior only by absence of compression flags. - if ctx.attr.compress == "preserve": - args.add("--dont_change_compression") - elif ctx.attr.compress == "yes": - args.add("--compression") - elif ctx.attr.compress == "no": - pass - else: - fail("\"compress\" attribute (%s) must be: yes, no, preserve." % ctx.attr.compress) - - if ctx.attr.exclude_build_data: - args.add("--exclude_build_data") - if ctx.attr.multi_release: - args.add("--multi_release") - - ctx.actions.run( - inputs = inputs, - outputs = [ctx.outputs.jar], - arguments = [args], - progress_message = "Merging into %s" % ctx.outputs.jar.short_path, - mnemonic = "JavaSingleJar", - executable = ctx.executable._singlejar, - use_default_shell_env = True, - ) - - files = depset([ctx.outputs.jar]) - providers = [DefaultInfo( - files = files, - runfiles = ctx.runfiles(transitive_files = files), - )] - if hasattr(java_common, "JavaRuntimeClasspathInfo"): - providers.append(java_common.JavaRuntimeClasspathInfo(runtime_classpath = inputs)) - return providers - -java_single_jar = rule( - attrs = { - "deps": attr.label_list( - allow_files = True, - doc = """ - The Java targets (including java_import and java_library) to collect - transitive dependencies from. Runtime dependencies are collected via - deps, exports, and runtime_deps. Resources are also collected. - Native cc_library or java_wrap_cc dependencies are not.""", - ), - "deploy_manifest_lines": attr.string_list(doc = """ - A list of lines to add to the META-INF/manifest.mf file."""), - "deploy_env": attr.label_list( - providers = [java_common.JavaRuntimeClasspathInfo] if hasattr(java_common, "JavaRuntimeClasspathInfo") else [], - allow_files = False, - doc = """ - A list of `java_binary` or `java_single_jar` targets which represent - the deployment environment for this binary. - - Set this attribute when building a plugin which will be loaded by another - `java_binary`. - - `deploy_env` dependencies are excluded from the jar built by this rule.""", - ), - "compress": attr.string(default = "preserve", doc = """ - Whether to always deflate ("yes"), always store ("no"), or pass - through unmodified ("preserve"). The default is "preserve", and is the - most efficient option -- no extra work is done to inflate or deflate."""), - "exclude_build_data": attr.bool(default = True, doc = """ - Whether to omit the build-data.properties file generated - by default."""), - "multi_release": attr.bool(default = True, doc = """Whether to enable Multi-Release output jars."""), - "_singlejar": attr.label( - default = Label("//toolchains:singlejar"), - cfg = "exec", - allow_single_file = True, - executable = True, - ), - }, - outputs = { - "jar": "%{name}.jar", - }, - implementation = _java_single_jar, - doc = """ -Collects Java dependencies and jar files into a single jar - -`java_single_jar` collects Java dependencies and jar files into a single jar. -This is similar to java_binary with everything related to executables disabled, -and provides an alternative to the java_binary "deploy jar hack". - -## Example - -```skylark -load("//tools/build_defs/java_single_jar:java_single_jar.bzl", "java_single_jar") - -java_single_jar( - name = "my_single_jar", - deps = [ - "//java/com/google/foo", - "//java/com/google/bar", - ], -) -``` - -Outputs: - {name}.jar: A single jar containing all of the inputs. -""", -) +java_single_jar = _java_single_jar diff --git a/java/private/BUILD b/java/private/BUILD index 939fa753..510c3010 100644 --- a/java/private/BUILD +++ b/java/private/BUILD @@ -23,10 +23,8 @@ bzl_library( bzl_library( name = "internals", srcs = [ - "boot_class_path_info.bzl", "java_common.bzl", "java_common_internal.bzl", - "java_info.bzl", "message_bundle_info.bzl", ], visibility = [ @@ -34,15 +32,37 @@ bzl_library( "@compatibility_proxy//:__pkg__", ], deps = [ + ":boot_class_path_info_bzl", + ":java_info_bzl", ":native_bzl", + "//java/common:semantics_bzl", + "//java/common/rules:java_helper_bzl", "//java/common/rules:toolchain_rules", - "//java/common/rules/impl:java_helper_bzl", "@bazel_skylib//lib:paths", + "@bazel_skylib//rules:common_settings", "@rules_cc//cc:find_cc_toolchain_bzl", "@rules_cc//cc/common", ], ) +bzl_library( + name = "boot_class_path_info_bzl", + srcs = ["boot_class_path_info.bzl"], + visibility = ["//java:__subpackages__"], + deps = ["@bazel_skylib//lib:paths"], +) + +bzl_library( + name = "java_info_bzl", + srcs = ["java_info.bzl"], + visibility = ["//java:__subpackages__"], + deps = [ + ":native_bzl", + "//java/common:semantics_bzl", + "@rules_cc//cc/common", + ], +) + # Exposed for use by the protobuf. bzl_library( name = "proto_support", diff --git a/java/private/java_common.bzl b/java/private/java_common.bzl index 70461632..59ba7dfc 100644 --- a/java/private/java_common.bzl +++ b/java/private/java_common.bzl @@ -16,12 +16,13 @@ load("@bazel_skylib//lib:paths.bzl", "paths") load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") load("//java/common/rules:java_runtime.bzl", "JavaRuntimeInfo") load("//java/common/rules:java_toolchain.bzl", "JavaToolchainInfo") -load("//java/common/rules/impl:java_helper.bzl", "helper") load(":boot_class_path_info.bzl", "BootClassPathInfo") load( ":java_common_internal.bzl", + _compile_header_internal = "compile_header", _compile_internal = "compile", _run_ijar_internal = "run_ijar", ) @@ -29,7 +30,6 @@ load( ":java_info.bzl", "JavaInfo", "JavaPluginInfo", - _java_info_add_constraints = "add_constraints", _java_info_make_non_strict = "make_non_strict", _java_info_merge = "merge", _java_info_set_annotation_processing = "set_annotation_processing", @@ -65,9 +65,7 @@ def _compile( sourcepath = [], resources = [], neverlink = False, - enable_annotation_processing = True, - add_exports = [], - add_opens = []): + enable_annotation_processing = True): return _compile_internal( ctx, output = output, @@ -90,8 +88,32 @@ def _compile( resources = resources, neverlink = neverlink, enable_annotation_processing = enable_annotation_processing, - add_exports = add_exports, - add_opens = add_opens, + ) + +def _compile_header( + ctx, + output, + java_toolchain, + source_jars = [], + source_files = [], + javac_opts = [], + deps = [], + plugins = [], + strict_deps = "ERROR", + bootclasspath = None, + enable_annotation_processing = True): + return _compile_header_internal( + ctx, + output = output, + java_toolchain = java_toolchain, + source_jars = source_jars, + source_files = source_files, + javac_opts = javac_opts, + deps = deps, + plugins = plugins, + strict_deps = strict_deps, + bootclasspath = bootclasspath, + enable_annotation_processing = enable_annotation_processing, ) def _run_ijar(actions, jar, java_toolchain, target_label = None): @@ -219,21 +241,6 @@ def _make_non_strict(java_info): def _get_message_bundle_info(): return None if semantics.IS_BAZEL else MessageBundleInfo -def _add_constraints(java_info, constraints = []): - """Returns a copy of the given JavaInfo with the given constraints added. - - Args: - java_info: (JavaInfo) The JavaInfo to enhance - constraints: ([str]) Constraints to add - - Returns: - (JavaInfo) - """ - if semantics.IS_BAZEL: - return java_info - - return _java_info_add_constraints(java_info, constraints = constraints) - def _get_constraints(java_info): """Returns a set of constraints added. @@ -297,13 +304,13 @@ def _make_java_common(): methods = { "provider": JavaInfo, "compile": _compile, + "compile_header": _compile_header, "run_ijar": _run_ijar, "stamp_jar": _stamp_jar, "pack_sources": _pack_sources, "default_javac_opts": _default_javac_opts, "default_javac_opts_depset": _default_javac_opts_depset, "merge": _merge, - "make_non_strict": _make_non_strict, "JavaPluginInfo": JavaPluginInfo, "JavaToolchainInfo": JavaToolchainInfo, "JavaRuntimeInfo": JavaRuntimeInfo, @@ -313,11 +320,14 @@ def _make_java_common(): if get_internal_java_common().google_legacy_api_enabled(): methods.update( MessageBundleInfo = _get_message_bundle_info(), # struct field that is None in bazel - add_constraints = _add_constraints, get_constraints = _get_constraints, set_annotation_processing = _set_annotation_processing, java_toolchain_label = _java_toolchain_label, ) + if semantics.IS_BAZEL: + methods.update( + make_non_strict = _make_non_strict, + ) return struct(**methods) java_common = _make_java_common() diff --git a/java/private/java_common_internal.bzl b/java/private/java_common_internal.bzl index 54f0c7bd..30d9533c 100644 --- a/java/private/java_common_internal.bzl +++ b/java/private/java_common_internal.bzl @@ -16,8 +16,8 @@ load("@bazel_skylib//lib:paths.bzl", "paths") load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") load("//java/common/rules:java_toolchain.bzl", "JavaToolchainInfo") -load("//java/common/rules/impl:java_helper.bzl", "helper") load( ":java_info.bzl", "JavaPluginInfo", @@ -37,6 +37,103 @@ _STRICT_DEPS_VALUES = [ "DEFAULT", # When no flag value is specified on the command line. ] +def _construct_javac_opts(ctx, java_toolchain, plugin_info, javac_opts, bootclasspath, add_exports = []): + all_javac_opts = [] # [depset[str]] + all_javac_opts.append(java_toolchain._javacopts) + all_javac_opts.append(ctx.fragments.java.default_javac_flags_depset) + all_javac_opts.append(semantics.compatible_javac_options(ctx, java_toolchain)) + + if ("com.google.devtools.build.runfiles.AutoBazelRepositoryProcessor" in + plugin_info.plugins.processor_classes.to_list()): + all_javac_opts.append(depset( + ["-Abazel.repository=" + ctx.label.repo_name], + order = "preorder", + )) + system_bootclasspath = None + for package_config in java_toolchain._package_configuration: + if package_config.matches(package_config.package_specs, ctx.label): + all_javac_opts.append(package_config.javac_opts) + if package_config.system: + if system_bootclasspath: + fail("Multiple system package configurations found for %s" % ctx.label) + system_bootclasspath = package_config.system + if not bootclasspath: + bootclasspath = system_bootclasspath + + all_javac_opts.append(depset( + ["--add-exports=%s=ALL-UNNAMED" % x for x in add_exports], + order = "preorder", + )) + + if type(javac_opts) == type([]): + # detokenize target's javacopts, it will be tokenized before compilation + all_javac_opts.append(helper.detokenize_javacopts(helper.tokenize_javacopts(ctx, javac_opts))) + elif type(javac_opts) == type(depset()): + all_javac_opts.append(javac_opts) + else: + fail("Expected javac_opts to be a list or depset, got:", type(javac_opts)) + + # we reverse the list of javacopts depsets, so that we keep the right-most set + # in case it's deduped. When this depset is flattened, we will reverse again, + # and then tokenize before passing to javac. This way, right-most javacopts will + # be retained and "win out". + return depset(order = "preorder", transitive = reversed(all_javac_opts)), bootclasspath + +def _construct_classpaths(deps, strict_deps, classpath_mode): + is_strict_mode = strict_deps != "OFF" + + direct_jars = depset() + if is_strict_mode: + direct_jars = depset(order = "preorder", transitive = [dep.compile_jars for dep in deps]) + + header_compilation_direct_deps = depset() + if is_strict_mode: + header_compilation_direct_deps = depset( + order = "preorder", + transitive = [dep.header_compilation_direct_deps for dep in deps], + ) + + compilation_classpath = depset( + order = "preorder", + transitive = [direct_jars] + [dep.transitive_compile_time_jars for dep in deps], + ) + compile_time_java_deps = depset() + if is_strict_mode and classpath_mode != "OFF": + compile_time_java_deps = depset(transitive = [dep._compile_time_java_dependencies for dep in deps]) + + return struct( + direct_jars = direct_jars, + header_compilation_direct_deps = header_compilation_direct_deps, + compilation_classpath = compilation_classpath, + compile_time_java_deps = compile_time_java_deps, + ) + +def _derive_header_compilation_outputs(ctx, base_output, suffix = ""): + if suffix: + compile_jar = _derive_output_file(ctx, base_output, name_suffix = suffix, extension = "jar") + compile_deps_proto = _derive_output_file(ctx, base_output, name_suffix = suffix, extension = "jdeps") + else: + compile_jar = base_output + compile_deps_proto = _derive_output_file(ctx, base_output, extension = "jdeps") + + # TODO: b/417791104 - remove check after a Bazel release + if ctx.fragments.java.use_header_compilation_direct_deps(): + header_compilation_jar = _derive_output_file(ctx, base_output, name_suffix = "-tjar", extension = "jar") + else: + header_compilation_jar = None + + return struct( + compile_jar = compile_jar, + header_compilation_jar = header_compilation_jar, + compile_deps_proto = compile_deps_proto, + ) + +def _validate_strict_deps(strict_deps): + strict_deps = (strict_deps or "default").upper() + if strict_deps not in _STRICT_DEPS_VALUES: + fail("Got an invalid value for strict_deps:", strict_deps, "must be one of:", _STRICT_DEPS_VALUES) + return strict_deps + def compile( ctx, output, @@ -125,54 +222,18 @@ def compile( get_internal_java_common().check_provider_instances([java_toolchain], "java_toolchain", JavaToolchainInfo) get_internal_java_common().check_provider_instances(plugins, "plugins", JavaPluginInfo) - # normalize and validate strict_deps - strict_deps = (strict_deps or "default").upper() - if strict_deps not in _STRICT_DEPS_VALUES: - fail("Got an invalid value for strict_deps:", strict_deps, "must be one of:", _STRICT_DEPS_VALUES) + strict_deps = _validate_strict_deps(strict_deps) plugin_info = merge_plugin_info_without_outputs(plugins + deps) - all_javac_opts = [] # [depset[str]] - all_javac_opts.append(java_toolchain._javacopts) - - all_javac_opts.append(ctx.fragments.java.default_javac_flags_depset) - all_javac_opts.append(semantics.compatible_javac_options(ctx, java_toolchain)) - - if ("com.google.devtools.build.runfiles.AutoBazelRepositoryProcessor" in - plugin_info.plugins.processor_classes.to_list()): - all_javac_opts.append(depset( - ["-Abazel.repository=" + ctx.label.workspace_name], - order = "preorder", - )) - system_bootclasspath = None - for package_config in java_toolchain._package_configuration: - if package_config.matches(package_config.package_specs, ctx.label): - all_javac_opts.append(package_config.javac_opts) - if package_config.system: - if system_bootclasspath: - fail("Multiple system package configurations found for %s" % ctx.label) - system_bootclasspath = package_config.system - if not bootclasspath: - bootclasspath = system_bootclasspath - - all_javac_opts.append(depset( - ["--add-exports=%s=ALL-UNNAMED" % x for x in add_exports], - order = "preorder", - )) - - if type(javac_opts) == type([]): - # detokenize target's javacopts, it will be tokenized before compilation - all_javac_opts.append(helper.detokenize_javacopts(helper.tokenize_javacopts(ctx, javac_opts))) - elif type(javac_opts) == type(depset()): - all_javac_opts.append(javac_opts) - else: - fail("Expected javac_opts to be a list or depset, got:", type(javac_opts)) - - # we reverse the list of javacopts depsets, so that we keep the right-most set - # in case it's deduped. When this depset is flattened, we will reverse again, - # and then tokenize before passing to javac. This way, right-most javacopts will - # be retained and "win out". - all_javac_opts = depset(order = "preorder", transitive = reversed(all_javac_opts)) + all_javac_opts, bootclasspath = _construct_javac_opts( + ctx, + java_toolchain, + plugin_info, + javac_opts, + bootclasspath, + add_exports, + ) # Optimization: skip this if there are no annotation processors, to avoid unnecessarily # disabling the direct classpath optimization if `enable_annotation_processor = False` @@ -190,27 +251,8 @@ def compile( has_sources = source_files or source_jars has_resources = resources or resource_jars - is_strict_mode = strict_deps != "OFF" classpath_mode = ctx.fragments.java.reduce_java_classpath() - - direct_jars = depset() - if is_strict_mode: - direct_jars = depset(order = "preorder", transitive = [dep.compile_jars for dep in deps]) - - header_compilation_direct_deps = depset() - if is_strict_mode: - header_compilation_direct_deps = depset( - order = "preorder", - transitive = [dep.header_compilation_direct_deps for dep in deps], - ) - - compilation_classpath = depset( - order = "preorder", - transitive = [direct_jars] + [dep.transitive_compile_time_jars for dep in deps], - ) - compile_time_java_deps = depset() - if is_strict_mode and classpath_mode != "OFF": - compile_time_java_deps = depset(transitive = [dep._compile_time_java_dependencies for dep in deps]) + classpaths = _construct_classpaths(deps, strict_deps, classpath_mode) # create compile time jar action if not has_sources: @@ -222,19 +264,10 @@ def compile( header_compilation_jar = compile_jar compile_deps_proto = None elif _should_use_header_compilation(ctx, java_toolchain): - compile_jar = helper.derive_output_file(ctx, output, name_suffix = "-hjar", extension = "jar") - - # TODO: b/417791104 - remove hasattr check once Bazel 8.3.0 is released - if hasattr(ctx.fragments.java, "use_header_compilation_direct_deps") and ctx.fragments.java.use_header_compilation_direct_deps(): - header_compilation_jar = helper.derive_output_file(ctx, output, name_suffix = "-tjar", extension = "jar") - header_compilation_extra_args = { - "header_compilation_jar": header_compilation_jar, - "header_compilation_direct_deps": header_compilation_direct_deps, - } - else: - header_compilation_jar = None - header_compilation_extra_args = {} - compile_deps_proto = helper.derive_output_file(ctx, output, name_suffix = "-hjar", extension = "jdeps") + hdr_outputs = _derive_header_compilation_outputs(ctx, output, suffix = "-hjar") + compile_jar = hdr_outputs.compile_jar + header_compilation_jar = hdr_outputs.header_compilation_jar + compile_deps_proto = hdr_outputs.compile_deps_proto get_internal_java_common().create_header_compilation_action( ctx, java_toolchain, @@ -243,17 +276,18 @@ def compile( plugin_info, depset(source_files), source_jars, - compilation_classpath, - direct_jars, + classpaths.compilation_classpath, + classpaths.direct_jars, bootclasspath, - compile_time_java_deps, + classpaths.compile_time_java_deps, all_javac_opts, strict_deps, ctx.label, injecting_rule_kind, enable_direct_classpath, annotation_processor_additional_inputs, - **header_compilation_extra_args + header_compilation_jar, + classpaths.header_compilation_direct_deps, ) elif ctx.fragments.java.use_ijars(): compile_jar = run_ijar( @@ -270,27 +304,27 @@ def compile( header_compilation_jar = compile_jar compile_deps_proto = None - native_headers_jar = helper.derive_output_file(ctx, output, name_suffix = "-native-header") - manifest_proto = helper.derive_output_file(ctx, output, extension_suffix = "_manifest_proto") + native_headers_jar = _derive_output_file(ctx, output, name_suffix = "-native-header") + manifest_proto = _derive_output_file(ctx, output, extension_suffix = "_manifest_proto") deps_proto = None if ctx.fragments.java.generate_java_deps() and has_sources: - deps_proto = helper.derive_output_file(ctx, output, extension = "jdeps") + deps_proto = _derive_output_file(ctx, output, extension = "jdeps") generated_class_jar = None generated_source_jar = None if uses_annotation_processing: - generated_class_jar = helper.derive_output_file(ctx, output, name_suffix = "-gen") - generated_source_jar = helper.derive_output_file(ctx, output, name_suffix = "-gensrc") + generated_class_jar = _derive_output_file(ctx, output, name_suffix = "-gen") + generated_source_jar = _derive_output_file(ctx, output, name_suffix = "-gensrc") get_internal_java_common().create_compilation_action( ctx, java_toolchain, output, manifest_proto, plugin_info, - compilation_classpath, - direct_jars, + classpaths.compilation_classpath, + classpaths.direct_jars, bootclasspath, depset(javabuilder_jvm_flags), - compile_time_java_deps, + classpaths.compile_time_java_deps, all_javac_opts, strict_deps, ctx.label, @@ -313,7 +347,7 @@ def compile( create_output_source_jar = len(source_files) > 0 or source_jars != [output_source_jar] if not output_source_jar: - output_source_jar = helper.derive_output_file(ctx, output, name_suffix = "-src", extension = "jar") + output_source_jar = _derive_output_file(ctx, output, name_suffix = "-src", extension = "jar") if create_output_source_jar: helper.create_single_jar( ctx.actions, @@ -335,7 +369,7 @@ def compile( # needs to be flattened because the public API is a list boot_classpath = (bootclasspath.bootclasspath if bootclasspath else java_toolchain.bootclasspath).to_list(), # we only add compile time jars from deps, and not exports - compilation_classpath = compilation_classpath, + compilation_classpath = classpaths.compilation_classpath, runtime_classpath = depset( order = "preorder", direct = direct_runtime_jars, @@ -368,6 +402,35 @@ def compile( compilation_info = compilation_info, ) +def _derive_output_file(ctx, base_file, *, name_suffix = "", extension = None, extension_suffix = ""): + """Declares a new file whose name is derived from the given file + + This method allows appending a suffix to the name (before extension), changing + the extension or appending a suffix after the extension. The new file is declared + as a sibling of the given base file. At least one of the three options must be + specified. It is an error to specify both `extension` and `extension_suffix`. + + Args: + ctx: (RuleContext) the rule context. + base_file: (File) the file from which to derive the resultant file. + name_suffix: (str) Optional. The suffix to append to the name before the + extension. + extension: (str) Optional. The new extension to use (without '.'). By default, + the base_file's extension is used. + extension_suffix: (str) Optional. The suffix to append to the base_file's extension + + Returns: + (File) the derived file + """ + if not name_suffix and not extension_suffix and not extension: + fail("At least one of name_suffix, extension or extension_suffix is required") + if extension and extension_suffix: + fail("only one of extension or extension_suffix can be specified") + if extension == None: + extension = base_file.extension + new_basename = paths.replace_extension(base_file.basename, name_suffix + "." + extension + extension_suffix) + return ctx.actions.declare_file(new_basename, sibling = base_file) + def _should_use_header_compilation(ctx, toolchain): if not ctx.fragments.java.use_header_compilation(): return False @@ -469,3 +532,108 @@ def get_runtime_classpath_for_archive(jars, excluded_jars): jars, excluded_jars, ) + +def compile_header( + ctx, + output, + java_toolchain, + source_jars = [], + source_files = [], + javac_opts = [], + deps = [], + plugins = [], + strict_deps = "ERROR", + bootclasspath = None, + injecting_rule_kind = None, + enable_annotation_processing = True): + """Compiles Java header jars from the implementation of a Starlark rule. + + Args: + ctx: (RuleContext) The rule context + output: (File) The output header jar (hjar) + java_toolchain: (JavaToolchainInfo) Toolchain to be used. Mandatory. + source_jars: ([File]) A list of the jars to be compiled. + source_files: ([File]) A list of the Java source files to be compiled. + javac_opts: ([str]|depset[str]) A list of the desired javac options. Optional. + deps: ([JavaInfo]) A list of dependencies. Optional. + plugins: ([JavaPluginInfo|JavaInfo]) A list of plugins. Optional. + strict_deps: (str) A string that specifies how to handle strict deps. Possible values: + 'OFF', 'ERROR', 'WARN' and 'DEFAULT'. + bootclasspath: (BootClassPathInfo) If present, overrides the bootclasspath associated with + the provided java_toolchain. Optional. + injecting_rule_kind: (str|None) + enable_annotation_processing: (bool) + + Returns: + (JavaInfo) + """ + get_internal_java_common().check_provider_instances([java_toolchain], "java_toolchain", JavaToolchainInfo) + get_internal_java_common().check_provider_instances(plugins, "plugins", JavaPluginInfo) + + strict_deps = _validate_strict_deps(strict_deps) + + plugin_info = merge_plugin_info_without_outputs(plugins + deps) + + all_javac_opts, bootclasspath = _construct_javac_opts( + ctx, + java_toolchain, + plugin_info, + javac_opts, + bootclasspath, + add_exports = [], + ) + + enable_direct_classpath = True + if not enable_annotation_processing and plugin_info.plugins.processor_classes: + plugin_info = disable_plugin_info_annotation_processing(plugin_info) + enable_direct_classpath = False + + classpaths = _construct_classpaths(deps, strict_deps, ctx.fragments.java.reduce_java_classpath()) + + hdr_outputs = _derive_header_compilation_outputs(ctx, output) + + get_internal_java_common().create_header_compilation_action( + ctx, + java_toolchain, + hdr_outputs.compile_jar, + hdr_outputs.compile_deps_proto, + plugin_info, + depset(source_files), + source_jars, + classpaths.compilation_classpath, + classpaths.direct_jars, + bootclasspath, + classpaths.compile_time_java_deps, + all_javac_opts, + strict_deps, + ctx.label, + injecting_rule_kind, + enable_direct_classpath, + [], # additional_inputs + hdr_outputs.header_compilation_jar, + classpaths.header_compilation_direct_deps, + ) + + return java_info_for_compilation( + output_jar = hdr_outputs.compile_jar, + compile_jar = hdr_outputs.compile_jar, + header_compilation_jar = hdr_outputs.header_compilation_jar, + source_jar = None, + generated_class_jar = None, + generated_source_jar = None, + plugin_info = plugin_info, + deps = deps, + runtime_deps = [], + exports = [], + exported_plugins = [], + compile_jdeps = hdr_outputs.compile_deps_proto, + jdeps = None, + native_headers_jar = None, + manifest_proto = None, + native_libraries = [], + neverlink = True, + add_exports = [], + add_opens = [], + direct_runtime_jars = [], + compilation_info = None, + ) diff --git a/java/private/java_info.bzl b/java/private/java_info.bzl index bf793c5a..e873ee1b 100644 --- a/java/private/java_info.bzl +++ b/java/private/java_info.bzl @@ -16,7 +16,6 @@ Definition of JavaInfo and JavaPluginInfo provider. """ -load("@rules_cc//cc/common:cc_common.bzl", "cc_common") load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load("//java/common:java_semantics.bzl", "semantics") load(":native.bzl", "get_internal_java_common") @@ -175,10 +174,11 @@ def merge( } if get_internal_java_common().google_legacy_api_enabled(): - cc_info = semantics.minimize_cc_info(cc_common.merge_cc_infos(cc_infos = [p.cc_link_params_info for p in providers])) + cc_info = semantics.minimize_cc_info(semantics.merge_cc_infos(cc_infos = [p.cc_link_params_info for p in providers])) result.update( cc_link_params_info = cc_info, - transitive_native_libraries = cc_info.transitive_native_libraries(), + transitive_native_libraries = + cc_info._legacy_transitive_native_libraries if hasattr(cc_info, "_legacy_transitive_native_libraries") else cc_info.transitive_native_libraries(), ) else: result.update( @@ -491,7 +491,7 @@ def java_info_for_compilation( runtime_output_jars = direct_runtime_jars, transitive_runtime_jars = transitive_runtime_jars, transitive_source_jars = depset( - direct = [source_jar], + direct = [source_jar] if source_jar else [], # only differs from the usual java_info.transitive_source_jars in the order of deps transitive = [dep.transitive_source_jars for dep in concatenated_deps.runtimedeps_exports_deps], ), @@ -676,17 +676,25 @@ def _javainfo_init_base( if get_internal_java_common().google_legacy_api_enabled(): transitive_cc_infos = [dep.cc_link_params_info for dep in concatenated_deps.runtimedeps_exports_deps] transitive_cc_infos.extend(native_libraries) - cc_info = semantics.minimize_cc_info(cc_common.merge_cc_infos(cc_infos = transitive_cc_infos)) + cc_info = semantics.minimize_cc_info(semantics.merge_cc_infos(cc_infos = transitive_cc_infos)) result.update( cc_link_params_info = cc_info, - transitive_native_libraries = cc_info.transitive_native_libraries(), + transitive_native_libraries = + cc_info._legacy_transitive_native_libraries if hasattr(cc_info, "_legacy_transitive_native_libraries") else cc_info.transitive_native_libraries(), ) else: + transitive_native_libraries = [] + if native_libraries: + merged_cc_info = semantics.merge_cc_infos(cc_infos = native_libraries) + if hasattr(merged_cc_info, "_legacy_transitive_native_libraries"): + transitive_native_libraries = [merged_cc_info._legacy_transitive_native_libraries] + else: + transitive_native_libraries = [merged_cc_info.transitive_native_libraries()] result.update( transitive_native_libraries = depset( order = "topological", transitive = [dep.transitive_native_libraries for dep in concatenated_deps.runtimedeps_exports_deps] + - ([cc_common.merge_cc_infos(cc_infos = native_libraries).transitive_native_libraries()] if native_libraries else []), + transitive_native_libraries, ), ) return result, concatenated_deps diff --git a/java/private/legacy_native.bzl b/java/private/legacy_native.bzl index 7a9e62fc..770434bc 100644 --- a/java/private/legacy_native.bzl +++ b/java/private/legacy_native.bzl @@ -17,6 +17,8 @@ """Lovely workaround to be able to expose native constants pretending to be Starlark.""" +# copybara: default visibility + # Unused with Bazel@HEAD, only used by the compatibility layer for older Bazel versions # buildifier: disable=native-java-common diff --git a/java/private/native.bzl b/java/private/native.bzl index be7ae686..cd45aa7a 100644 --- a/java/private/native.bzl +++ b/java/private/native.bzl @@ -14,6 +14,8 @@ """Redirects for private native APIs""" +# copybara: default visibility + # Used for some private native APIs that we can't replicate just yet in Starlark def get_internal_java_common(): return java_common.internal_DO_NOT_USE() # buildifier: disable=native-java-common diff --git a/java/repositories.bzl b/java/repositories.bzl index 2af22140..df95f86d 100644 --- a/java/repositories.bzl +++ b/java/repositories.bzl @@ -22,33 +22,39 @@ load("//toolchains:remote_java_repository.bzl", "remote_java_repository") # visible for tests JAVA_TOOLS_CONFIG = { - "version": "v16.0", + "version": "v19.0", + "source_revision": "61972bfd7fb6f587fc4576b5114e20758b501806", "release": "true", "artifacts": { "java_tools_linux": { - "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v16.0/java_tools_linux-v16.0.zip", - "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v16.0/java_tools_linux-v16.0.zip", - "sha": "7c360c60da9b9079e31f18de198f23a22555dfb7b6e91e3c6a7103127b1a8538", + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools_linux-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools_linux-v19.0.zip", + "sha": "7d5b0c01f99ea5596b7901a7e5f9173f3ae3c4f0b480378e87567eaf97d75d25", + }, + "java_tools_linux_aarch64": { + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools_linux_aarch64-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools_linux_aarch64-v19.0.zip", + "sha": "34b14fdfe8d6e32ed7f80e7c4d34ce79f4006e0d4b621552f507e51b9d6a3d7d", }, "java_tools_windows": { - "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v16.0/java_tools_windows-v16.0.zip", - "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v16.0/java_tools_windows-v16.0.zip", - "sha": "b41faa85fceeb2f852e48d51d000d3bf4f29da86ee61d0fc8cca46d297bccf22", + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools_windows-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools_windows-v19.0.zip", + "sha": "86c5a58ccefdb9e704fddd325f5fbc7867b2cdd128fb8b9abfdf607a75d2ae71", }, "java_tools_darwin_x86_64": { - "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v16.0/java_tools_darwin_x86_64-v16.0.zip", - "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v16.0/java_tools_darwin_x86_64-v16.0.zip", - "sha": "a41de64afb663bb4880af52b55886098241b9222ee8ec1a0f6258d006ba247fb", + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools_darwin_x86_64-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools_darwin_x86_64-v19.0.zip", + "sha": "78ff8ec7038ab5f9cd261cdf9ff75ea0eb2af7579f9aeef9d658459ee37fabac", }, "java_tools_darwin_arm64": { - "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v16.0/java_tools_darwin_arm64-v16.0.zip", - "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v16.0/java_tools_darwin_arm64-v16.0.zip", - "sha": "b79900dccca7c26fbae9a38c4da80987445e07194517ec53e169c45f1a88c7be", + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools_darwin_arm64-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools_darwin_arm64-v19.0.zip", + "sha": "86f15280dd0ce121a22f061e2e301ecf746597caa4938cf56852b3d311b830d8", }, "java_tools": { - "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v16.0/java_tools-v16.0.zip", - "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v16.0/java_tools-v16.0.zip", - "sha": "d8b126078705e91677db67b05f7b25ad6fa8865949e2dd38ff85e0553bfb0be2", + "mirror_url": "https://mirror.bazel.build/bazel_java_tools/releases/java/v19.0/java_tools-v19.0.zip", + "github_url": "https://github.com/bazelbuild/java_tools/releases/download/java_v19.0/java_tools-v19.0.zip", + "sha": "d21d4aad1a18062512bcf4e8f7a09a4f5a042c760daa779e0ddda6e41b170507", }, }, } @@ -80,41 +86,41 @@ _REMOTE_JDK_CONFIGS_LIST = [ struct( name = "remote_jdk8_linux_aarch64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"], - sha256 = "3ae6b27727a308c0c262a99e20af29c87aad7910de423db2607c44551b598e57", - strip_prefix = "zulu8.84.0.15-ca-jdk8.0.442-linux_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-linux_aarch64.tar.gz"], + sha256 = "c372fb26480c052537125013cb0ba7336c404e5190ea8f6e2de247b676432a67", + strip_prefix = "zulu8.90.0.19-ca-jdk8.0.472-linux_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-linux_aarch64.tar.gz"], version = "8", ), struct( name = "remote_jdk8_linux", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], - sha256 = "6e3bd4d911e6eb2d14e0b48e622b6909c76add0b51c51d11f5c2c3d2a045bcf3", - strip_prefix = "zulu8.84.0.15-ca-jdk8.0.442-linux_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-linux_x64.tar.gz"], + sha256 = "6f9e3fa773829ac2553411fb0cdeb394980627c47c9ab8f8892d4b917b70e2dd", + strip_prefix = "zulu8.90.0.19-ca-jdk8.0.472-linux_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-linux_x64.tar.gz"], version = "8", ), struct( name = "remote_jdk8_macos_aarch64", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], - sha256 = "effa6d1bd4b6bce68328df66e063a97c2c4afeb0aa36fda4f85c434dd8246572", - strip_prefix = "zulu8.84.0.15-ca-jdk8.0.442-macosx_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-macosx_aarch64.tar.gz"], + sha256 = "823d547ab9508e3a2b8abd3c5de66a39a50a254dc5835747cf3c2617fbe55600", + strip_prefix = "zulu8.90.0.19-ca-jdk8.0.472-macosx_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-macosx_aarch64.tar.gz"], version = "8", ), struct( name = "remote_jdk8_macos", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:x86_64"], - sha256 = "52131294512042dd6356426202e6a4116536477281fe76cfc0a3a15fe0d6ff44", - strip_prefix = "zulu8.84.0.15-ca-jdk8.0.442-macosx_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-macosx_x64.tar.gz"], + sha256 = "96fb7bc3a2babd7f807484b1b8f1dfb8cf2c61ea27b2d0630e2237088b0a5100", + strip_prefix = "zulu8.90.0.19-ca-jdk8.0.472-macosx_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-macosx_x64.tar.gz"], version = "8", ), struct( name = "remote_jdk8_windows", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"], - sha256 = "551c0df372a4b01754e214c52d2bdc2e22e1582274a3ea0e4a27d77db6a9cbea", - strip_prefix = "zulu8.84.0.15-ca-jdk8.0.442-win_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.84.0.15-ca-jdk8.0.442-win_x64.zip"], + sha256 = "ff90484103d3fdb9808f737af027586c8dbfa1aa8a310ce99b0b5e0517567aee", + strip_prefix = "zulu8.90.0.19-ca-jdk8.0.472-win_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu8.90.0.19-ca-jdk8.0.472-win_x64.zip"], version = "8", ), struct( @@ -128,203 +134,275 @@ _REMOTE_JDK_CONFIGS_LIST = [ struct( name = "remotejdk11_linux_aarch64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"], - sha256 = "f221d794325ab04382ba52250fc8fe8c4d384841a63bc2acd62d623a5bc53eb7", - strip_prefix = "zulu11.78.15-ca-jdk11.0.26-linux_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-linux_aarch64.tar.gz"], + sha256 = "5a225a0fe0a92bc6c04c8c5aeb03c697c6fd114465829f23e494a2ad44fa1cc0", + strip_prefix = "zulu11.84.17-ca-jdk11.0.29-linux_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-linux_aarch64.tar.gz"], version = "11", ), struct( name = "remotejdk11_linux", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], - sha256 = "fdf95b001d50b03bc3ce5f4fe7dc96bec9f94e561f9ec722a149bd7995600449", - strip_prefix = "zulu11.78.15-ca-jdk11.0.26-linux_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-linux_x64.tar.gz"], + sha256 = "681b2e4bf7fedf4d20666fc2a954b83ff5675ccfb916c867267d29c85c2ee310", + strip_prefix = "zulu11.84.17-ca-jdk11.0.29-linux_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-linux_x64.tar.gz"], version = "11", ), struct( name = "remotejdk11_macos_aarch64", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], - sha256 = "3708badcc0c79fc1791e74b62478188a1f43c4f9a1e7d3e1bd4173da995479a3", - strip_prefix = "zulu11.78.15-ca-jdk11.0.26-macosx_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-macosx_aarch64.tar.gz"], + sha256 = "09ed1734c2d88fadcb75fdbec1ba5467d32e7fa2b10894541aa8e3d3ce78dc2d", + strip_prefix = "zulu11.84.17-ca-jdk11.0.29-macosx_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-macosx_aarch64.tar.gz"], version = "11", ), struct( name = "remotejdk11_macos", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:x86_64"], - sha256 = "bb3884619c6f09ec5ca3ce43810c61ade647bb896f4120a6cf076ec993b5a1a0", - strip_prefix = "zulu11.78.15-ca-jdk11.0.26-macosx_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-macosx_x64.tar.gz"], + sha256 = "b7f5a37c47ed94af1c8ecf631b1dc6dec990958f3afd4222a7dd27d6ca1084bd", + strip_prefix = "zulu11.84.17-ca-jdk11.0.29-macosx_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-macosx_x64.tar.gz"], version = "11", ), struct( name = "remotejdk11_win", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"], - sha256 = "2f48346ba05d0d1a31a6797cd0fd27a0492c0df0c90730c9eeca7fc6952a075c", - strip_prefix = "zulu11.78.15-ca-jdk11.0.26-win_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.78.15-ca-jdk11.0.26-win_x64.zip"], + sha256 = "f4002a8090662ff66bf9f3248604be0f9d226e964085bd59bbea4b8535df3de1", + strip_prefix = "zulu11.84.17-ca-jdk11.0.29-win_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu11.84.17-ca-jdk11.0.29-win_x64.zip"], version = "11", ), struct( name = "remotejdk11_linux_ppc64le", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:ppc64le"], - sha256 = "42c63651125a149cee2ba781300d75ffa67a25032f95038d50ee6d6177cb2e41", - strip_prefix = "jdk-11.0.26+4", - urls = ["https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.26+4/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.26_4.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.26+4/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.26_4.tar.gz"], + sha256 = "e272abd162b3de68093630929453feba3e63a5ab1bbb912379f6a4aa968ef06a", + strip_prefix = "jdk-11.0.28+6", + urls = ["https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.28+6/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.28_6.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.28+6/OpenJDK11U-jdk_ppc64le_linux_hotspot_11.0.28_6.tar.gz"], version = "11", ), struct( name = "remotejdk11_linux_s390x", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:s390x"], - sha256 = "0da13d990da34ecc666399cf0efa72a4b4e295f05c0686ea25a4a173a6f4414b", - strip_prefix = "jdk-11.0.26+4", - urls = ["https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.26+4/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.26_4.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.26+4/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.26_4.tar.gz"], + sha256 = "ac3f94fdcc5372e90f44fad9cd03ec0e3fd3535fea06c120f85e4a7534c6de04", + strip_prefix = "jdk-11.0.28+6", + urls = ["https://github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.28+6/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.28_6.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin11-binaries/releases/download/jdk-11.0.28+6/OpenJDK11U-jdk_s390x_linux_hotspot_11.0.28_6.tar.gz"], version = "11", ), struct( name = "remotejdk11_win_arm64", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:arm64"], - sha256 = "1d10cf760e4e011e830ef18ab28453a742ac84c046e4e77759e81b58716e6a8b", - strip_prefix = "jdk-11.0.26+4", - urls = ["https://aka.ms/download-jdk/microsoft-jdk-11.0.26-windows-aarch64.zip", "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.26-windows-aarch64.zip"], + sha256 = "1e7bfad513a1c2930000db1af19c813460c7a788503c39a7f1f27375310880f8", + strip_prefix = "jdk-11.0.28+6", + urls = ["https://aka.ms/download-jdk/microsoft-jdk-11.0.28-windows-aarch64.zip", "https://mirror.bazel.build/aka.ms/download-jdk/microsoft-jdk-11.0.28-windows-aarch64.zip"], version = "11", ), struct( name = "remotejdk17_linux_aarch64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"], - sha256 = "9fe5d08b20546e84af517cfefc7068f7a47e98473603782264e519f935977cb3", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-linux_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-linux_aarch64.tar.gz"], + sha256 = "527b76fbd60e8f9644f6b70800d15160cdbd3344bc6fbf30d42e905f540a770c", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-linux_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-linux_aarch64.tar.gz"], version = "17", ), struct( name = "remotejdk17_linux", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], - sha256 = "37ab75b2f5da0ff0db973b31e9d9f14f729137a0a110abd6472ac8c6f2feabb6", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-linux_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-linux_x64.tar.gz"], + sha256 = "1dcbbed73e95dc35f5c60402a84936f6830ff43c2a0dc0037a5657dbc25472c1", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-linux_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-linux_x64.tar.gz"], version = "17", ), struct( name = "remotejdk17_macos_aarch64", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], - sha256 = "c3b9bfb0a6dbe4c5d9efce6c46d3a89c92d7b07ba1bd0afc944612298ac284ec", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-macosx_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-macosx_aarch64.tar.gz"], + sha256 = "5558f7efe6297ecb20f422f31471555cd43e9499beb304b8f3ddc68796d2874b", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-macosx_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-macosx_aarch64.tar.gz"], version = "17", ), struct( name = "remotejdk17_macos", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:x86_64"], - sha256 = "ee1a55b6b63d62d1a24d420b1550ef1736fda36db0e612893d9d26eb1d7f1611", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-macosx_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-macosx_x64.tar.gz"], + sha256 = "e6b2fb0cd3f929225a179c2fb2813abd1834f839a3b4c8cdcb36067aa16b6f83", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-macosx_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-macosx_x64.tar.gz"], version = "17", ), struct( name = "remotejdk17_win_arm64", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:arm64"], - sha256 = "dbf51756115f7591759b2ed6d9c0d79b3b770c1a13be476c99d64934a93ff422", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-win_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-win_aarch64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-win_aarch64.zip"], + sha256 = "c1bba9148907348da93b0de2c9abd56bd180efcb6b1f35068ab9785015fcd74b", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-win_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-win_aarch64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-win_aarch64.zip"], version = "17", ), struct( name = "remotejdk17_win", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"], - sha256 = "11dbe0051cea65fbfc94e0074fbb26d81897f5aff2df69fed3784f380d0d9ec9", - strip_prefix = "zulu17.56.15-ca-jdk17.0.14-win_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.56.15-ca-jdk17.0.14-win_x64.zip"], + sha256 = "bd8a942bb543f109a28d3eadf3ec2f29a3ee28ab53506e31d2858292f63c6949", + strip_prefix = "zulu17.62.17-ca-jdk17.0.17-win_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu17.62.17-ca-jdk17.0.17-win_x64.zip"], version = "17", ), struct( name = "remotejdk17_linux_ppc64le", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:ppc64le"], - sha256 = "f4cb9ee5906a44d110fa381310cd7181d95498d27087d449e7e9b74bddd9def2", - strip_prefix = "jdk-17.0.14+7", - urls = ["https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14+7/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.14_7.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14+7/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.14_7.tar.gz"], + sha256 = "eb020f74e00870379522be0b44fc6322c2214e77971c258400c8b5af704d5c0a", + strip_prefix = "jdk-17.0.16+8", + urls = ["https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16+8/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.16_8.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16+8/OpenJDK17U-jdk_ppc64le_linux_hotspot_17.0.16_8.tar.gz"], version = "17", ), struct( name = "remotejdk17_linux_s390x", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:s390x"], - sha256 = "3a1d896eb3a737020e5ec95ec3206b1ca36cb365538382289d3fb46d14303648", - strip_prefix = "jdk-17.0.14+7", - urls = ["https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14+7/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.14_7.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.14+7/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.14_7.tar.gz"], + sha256 = "03dd99d34d2d1b88395765df3acbec2cb81de286f64b1d9e6df3682bee365168", + strip_prefix = "jdk-17.0.16+8", + urls = ["https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16+8/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.16_8.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.16+8/OpenJDK17U-jdk_s390x_linux_hotspot_17.0.16_8.tar.gz"], version = "17", ), struct( name = "remotejdk21_linux_aarch64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"], - sha256 = "2cab003bad25100a00b818ce229455d35ece03fc2e69be32c9c1c03f90b2eb89", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-linux_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-linux_aarch64.tar.gz"], + sha256 = "a826a93c18d4388ec8d5d4057f5bb1b5c60f00ffc875ed299dea17aa947555ee", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-linux_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-linux_aarch64.tar.gz"], version = "21", ), struct( name = "remotejdk21_linux", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], - sha256 = "5daff61d307d18305a4022c56013cbaa8987a7dd103e310ebbeb75e0f3091a03", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-linux_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-linux_x64.tar.gz"], + sha256 = "67e810b31427ac0ff1c249473595066a00bdf0f9265df186c32905d5f75c93b8", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-linux_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-linux_x64.tar.gz"], version = "21", ), struct( name = "remotejdk21_macos_aarch64", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], - sha256 = "1d6385f17ae2dc3b57a6d1b6fd6aeadafe1c7138bc744f62a767851eececd092", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-macosx_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-macosx_aarch64.tar.gz"], + sha256 = "b56112ad12d3dfe62802840655ecf198fe4ca48729824c939d65a69e803536c7", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-macosx_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-macosx_aarch64.tar.gz"], version = "21", ), struct( name = "remotejdk21_macos", target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:x86_64"], - sha256 = "0b0f05e53e2b85f3881f1b8f5e3ef7e2e992796a1872afbc851b73127b16933d", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-macosx_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-macosx_x64.tar.gz"], + sha256 = "3d870d823e3e101189b00ad975188c0321e31056ac8ca8b487bcf4454f3b5cfe", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-macosx_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-macosx_x64.tar.gz"], version = "21", ), struct( name = "remotejdk21_win_arm64", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:arm64"], - sha256 = "57c568355b97d288f12b720760d802b1a19c55e9b0707a5c2ad76d34fd893db8", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-win_aarch64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-win_aarch64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-win_aarch64.zip"], + sha256 = "1210b169db7b40d7305a94d41ab3eb87aaee51108b43f8f7f36f0c2865107790", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-win_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-win_aarch64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-win_aarch64.zip"], version = "21", ), struct( name = "remotejdk21_win", target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"], - sha256 = "a1360d2ab3ee9932b5cb20a2386d6b0fb1518a68c89a08739736c38a4debbdae", - strip_prefix = "zulu21.40.17-ca-jdk21.0.6-win_x64", - urls = ["https://cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.40.17-ca-jdk21.0.6-win_x64.zip"], + sha256 = "0c9812c0fe527b59f48c70cb527035c8a7abe620b31f776b4ddc21bddc1cd067", + strip_prefix = "zulu21.46.19-ca-jdk21.0.9-win_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu21.46.19-ca-jdk21.0.9-win_x64.zip"], version = "21", ), struct( name = "remotejdk21_linux_ppc64le", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:ppc64le"], - sha256 = "163724b70b86d5a8461f85092165a9cc5a098ed900fee90d1b0c0be9607ae3d2", - strip_prefix = "jdk-21.0.6+7", - urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_ppc64le_linux_hotspot_21.0.6_7.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_ppc64le_linux_hotspot_21.0.6_7.tar.gz"], + sha256 = "a24e869b8e563fd7b9f7776f6686ca5d737c8d1c3c33c9b72836935709b44a34", + strip_prefix = "jdk-21.0.8+9", + urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_ppc64le_linux_hotspot_21.0.8_9.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_ppc64le_linux_hotspot_21.0.8_9.tar.gz"], version = "21", ), struct( name = "remotejdk21_linux_riscv64", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:riscv64"], - sha256 = "203796e4ba2689aa921b5e0cdc9e02984d88622f80fcb9acb05a118b05007be8", - strip_prefix = "jdk-21.0.6+7", - urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_riscv64_linux_hotspot_21.0.6_7.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_riscv64_linux_hotspot_21.0.6_7.tar.gz"], + sha256 = "8171d95189e675e297b5cb96c7ac6247ab4e9f48da82b13f491fc46ef5d97836", + strip_prefix = "jdk-21.0.8+9", + urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_riscv64_linux_hotspot_21.0.8_9.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_riscv64_linux_hotspot_21.0.8_9.tar.gz"], version = "21", ), struct( name = "remotejdk21_linux_s390x", target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:s390x"], - sha256 = "5ba742c87d48fcf564def56812699f6499a1cfd3535ae43286e94e74b8165faf", - strip_prefix = "jdk-21.0.6+7", - urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_s390x_linux_hotspot_21.0.6_7.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6+7/OpenJDK21U-jdk_s390x_linux_hotspot_21.0.6_7.tar.gz"], + sha256 = "a84e3cbf8bb5f8a313e06b790c7bc388687ba00262e981f5e33432ebd4d34356", + strip_prefix = "jdk-21.0.8+9", + urls = ["https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_s390x_linux_hotspot_21.0.8_9.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.8+9/OpenJDK21U-jdk_s390x_linux_hotspot_21.0.8_9.tar.gz"], version = "21", ), + struct( + name = "remotejdk25_linux_aarch64", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:aarch64"], + sha256 = "f7295abb1decb2f6e0ea9f760a70917f2d47356db4366d615c7ab9b01c3c6866", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-linux_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-linux_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-linux_aarch64.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_linux", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:x86_64"], + sha256 = "f1752d0051b6ca233625ddb2c18c9170edbe55c5ee6515bfefd8ea0197ee1c20", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-linux_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-linux_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-linux_x64.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_macos_aarch64", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:aarch64"], + sha256 = "537ac74fa1ca2c4dd8f6063ddede0138ae4a896f128bfe10b428a7dcc4aa929f", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-macosx_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-macosx_aarch64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-macosx_aarch64.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_macos", + target_compatible_with = ["@platforms//os:macos", "@platforms//cpu:x86_64"], + sha256 = "fe22346c192920c5b84b23f4aa24e3debb0bb94fc428016f7c2b2c7790c82780", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-macosx_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-macosx_x64.tar.gz", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-macosx_x64.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_win_arm64", + target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:arm64"], + sha256 = "5f44792a12af2100b4db9b5120c27c42af8080ad63bc9eaadc9ca25e5c7dd590", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-win_aarch64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-win_aarch64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-win_aarch64.zip"], + version = "25", + ), + struct( + name = "remotejdk25_win", + target_compatible_with = ["@platforms//os:windows", "@platforms//cpu:x86_64"], + sha256 = "90bcbbcbe2fb7aec43ce8fd2efa024fcc48f00bbdcd7a76b58f912d6b97e6d56", + strip_prefix = "zulu25.32.17-ca-jdk25.0.2-win_x64", + urls = ["https://cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-win_x64.zip", "https://mirror.bazel.build/cdn.azul.com/zulu/bin/zulu25.32.17-ca-jdk25.0.2-win_x64.zip"], + version = "25", + ), + struct( + name = "remotejdk25_linux_ppc64le", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:ppc64le"], + sha256 = "b262b735b215173003766da36588d5f717dceada0286db41b439f93fb2ada468", + strip_prefix = "jdk-25.0.2+10", + urls = ["https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_ppc64le_linux_hotspot_25.0.2_10.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_ppc64le_linux_hotspot_25.0.2_10.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_linux_riscv64", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:riscv64"], + sha256 = "168119e4fba350f4e6b3ca92450a2b90a8502b89a235a04415e9adf9f5d3164e", + strip_prefix = "jdk-25.0.2+10", + urls = ["https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_riscv64_linux_hotspot_25.0.2_10.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_riscv64_linux_hotspot_25.0.2_10.tar.gz"], + version = "25", + ), + struct( + name = "remotejdk25_linux_s390x", + target_compatible_with = ["@platforms//os:linux", "@platforms//cpu:s390x"], + sha256 = "15e5cbcadcf3d43623c31b825063cdc2817b9f1ba840b51dc6ef70e5d33c84e3", + strip_prefix = "jdk-25.0.2+10", + urls = ["https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_s390x_linux_hotspot_25.0.2_10.tar.gz", "https://mirror.bazel.build/github.com/adoptium/temurin25-binaries/releases/download/jdk-25.0.2+10/OpenJDK25U-jdk_s390x_linux_hotspot_25.0.2_10.tar.gz"], + version = "25", + ), ] def _make_version_to_remote_jdks(): @@ -369,6 +447,10 @@ def remote_jdk21_repos(): """Imports OpenJDK 21 repositories.""" _remote_jdk_repos_for_version("21") +def remote_jdk25_repos(): + """Imports OpenJDK 25 repositories.""" + _remote_jdk_repos_for_version("25") + def rules_java_dependencies(): """DEPRECATED: No-op, kept for backwards compatibility""" print("DEPRECATED: use rules_java_dependencies() from rules_java_deps.bzl") # buildifier: disable=print @@ -384,6 +466,7 @@ def rules_java_toolchains(name = "toolchains"): remote_jdk11_repos() remote_jdk17_repos() remote_jdk21_repos() + remote_jdk25_repos() java_tools_repos() native.register_toolchains( diff --git a/java/rules_java_deps.bzl b/java/rules_java_deps.bzl index b32edd24..b2086dc1 100644 --- a/java/rules_java_deps.bzl +++ b/java/rules_java_deps.bzl @@ -1,12 +1,11 @@ """Module extension for compatibility with previous Bazel versions""" +load("@bazel_features//private:util.bzl", _bazel_version_ge = "ge") load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe") def _compatibility_proxy_repo_impl(rctx): - # TODO: use @bazel_features - bazel = native.bazel_version - if not bazel or bazel >= "8": + if _bazel_version_ge("8.0.0"): rctx.file( "BUILD.bazel", """ @@ -210,13 +209,15 @@ def rules_license_repo(): ], ) -def bazel_features_repo(): +def re2_repo(): maybe( http_archive, - name = "bazel_features", - sha256 = "a660027f5a87f13224ab54b8dc6e191693c554f2692fcca46e8e29ee7dabc43b", - strip_prefix = "bazel_features-1.30.0", - url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.30.0/bazel_features-v1.30.0.tar.gz", + name = "re2", + sha256 = "5bb6875ae1cd1e9fedde98018c346db7260655f86fdb8837e3075103acd3649b", + strip_prefix = "re2-2023-09-01", + urls = [ + "https://github.com/google/re2/releases/download/2023-09-01/re2-2023-09-01.tar.gz", + ], ) def rules_java_dependencies(): @@ -232,4 +233,4 @@ def rules_java_dependencies(): zlib_repo() absl_repo() rules_license_repo() - bazel_features_repo() + re2_repo() diff --git a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/BUILD b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/BUILD index 5b521a9b..11b8ae0f 100644 --- a/java/runfiles/src/main/java/com/google/devtools/build/runfiles/BUILD +++ b/java/runfiles/src/main/java/com/google/devtools/build/runfiles/BUILD @@ -1,4 +1,5 @@ -load("//java:defs.bzl", "java_library", "java_plugin") +load("//java:java_library.bzl", "java_library") +load("//java:java_plugin.bzl", "java_plugin") package(default_applicable_licenses = ["@rules_java//:license"]) diff --git a/java/testutil.bzl b/java/testutil.bzl index 6207583b..4063ea6f 100644 --- a/java/testutil.bzl +++ b/java/testutil.bzl @@ -5,6 +5,8 @@ # TODO: consider eventually upstreaming to rules_cc def _cc_info_transitive_native_libraries(cc_info): + if hasattr(cc_info, "_legacy_transitive_native_libraries"): + return cc_info._legacy_transitive_native_libraries return cc_info.transitive_native_libraries() def _cc_library_to_link_static_library(library_to_link): diff --git a/test/BUILD.bazel b/test/BUILD.bazel index 084ff40c..9d133ce7 100644 --- a/test/BUILD.bazel +++ b/test/BUILD.bazel @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -load("@bazel_skylib//rules:diff_test.bzl", "diff_test") load("@rules_shell//shell:sh_test.bzl", "sh_test") load("//java:repositories.bzl", "JAVA_TOOLS_CONFIG", "REMOTE_JDK_CONFIGS") load(":check_remotejdk_configs_match.bzl", "validate_configs") @@ -48,6 +47,7 @@ sh_test( ]) for name, config in JAVA_TOOLS_CONFIG["artifacts"].items() ], + tags = ["manual"], # explicitly tested only on Linux ) sh_test( @@ -61,18 +61,6 @@ sh_test( tags = ["manual"], # explicitly tested only on Linux ) -diff_test( - name = "docs_up_to_date_test", - failure_message = """ - Docs are no longer up to date. Regenerate them by running: - - bazel build //java/docs:rules_docs && \ - cp bazel-bin/java/docs/rules_docs.out java/docs/rules.md - """, - file1 = "//java/docs:rules.md", - file2 = "//java/docs:rules_docs", -) - validate_configs() starlark_doc_extract( @@ -80,3 +68,9 @@ starlark_doc_extract( src = "@compatibility_proxy//:proxy.bzl", deps = ["@compatibility_proxy//:proxy_bzl"], ) + +starlark_doc_extract( + name = "java_single_jar_bzl_graph", + src = "//java:java_single_jar.bzl", + deps = ["//java:java_single_jar"], +) diff --git a/test/check_remote_java_tools_configs.sh b/test/check_remote_java_tools_configs.sh index 7e69dc00..957aa788 100755 --- a/test/check_remote_java_tools_configs.sh +++ b/test/check_remote_java_tools_configs.sh @@ -22,7 +22,11 @@ function download_and_check_hash() { TMP_FILE=$(mktemp -q /tmp/remotejavatools.XXXXXX) echo "fetching $name from $url to ${TMP_FILE}" curl --silent -o ${TMP_FILE} -L "$url" - actual_hash=`sha256sum ${TMP_FILE} | cut -d' ' -f1` + if command -v sha256sum &> /dev/null; then + actual_hash=`sha256sum ${TMP_FILE} | cut -d' ' -f1` + else + actual_hash=`shasum -a 256 ${TMP_FILE} | cut -d' ' -f1` + fi if [ "${hash}" != "${actual_hash}" ]; then echo "ERROR: wrong hash for ${name}! wanted: ${hash}, got: ${actual_hash}" exit 1 diff --git a/test/check_remote_jdk_configs.sh b/test/check_remote_jdk_configs.sh index 1b58c96d..b1c509fe 100755 --- a/test/check_remote_jdk_configs.sh +++ b/test/check_remote_jdk_configs.sh @@ -40,12 +40,12 @@ for config in "$@"; do fi if [[ -n "${mirror_url}" ]]; then echo "checking mirror: ${mirror_url}" - curl --silent --fail -I -L ${mirror_url} > /dev/null || { _MISSING_MIRRORS+=("${mirror_url}"); } + curl --silent --fail -I -L ${mirror_url} > /dev/null || { _MISSING_MIRRORS+=("${url}"); } fi done if [[ ${#_MISSING_MIRRORS[@]} -gt 0 ]]; then - echo "Missing mirror URLs:" + echo "URLs that aren't mirrored:" for m in "${_MISSING_MIRRORS[@]}"; do echo " ${m}" done diff --git a/test/java/bazel/common/BUILD.bazel b/test/java/bazel/common/BUILD.bazel new file mode 100644 index 00000000..c9cd0668 --- /dev/null +++ b/test/java/bazel/common/BUILD.bazel @@ -0,0 +1,6 @@ +load(":java_common_tests.bzl", "java_common_tests") +load(":java_info_tests.bzl", "java_info_tests") + +java_common_tests(name = "java_common_tests") + +java_info_tests(name = "java_info_tests") diff --git a/test/java/bazel/common/java_common_tests.bzl b/test/java/bazel/common/java_common_tests.bzl new file mode 100644 index 00000000..80fdf442 --- /dev/null +++ b/test/java/bazel/common/java_common_tests.bzl @@ -0,0 +1,41 @@ +"""Bazel tests for java_common APIs""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") + +def _test_java_common_pack_sources_with_external_resource(name): + util.helper_target( + custom_java_info_rule, + name = name + "/custom", + output_jar = name + "/custom.jar", + sources = [ + ":InternalLib.java", + "@other_repo//:ExternalLib.java", + ], + pack_sources = True, + ) + + analysis_test( + name = name, + impl = _test_java_common_pack_sources_with_external_resource_impl, + target = name + "/custom", + # Bazel 7 names external repos differently + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_java_common_pack_sources_with_external_resource_impl(env, target): + assert_that_action = env.expect.that_target(target).action_generating("{package}/{name}-src.jar") + assert_that_action.argv().contains_at_least([ + "--resources", + "{package}/InternalLib.java:bazel/common/InternalLib.java", + "external/+test_repositories_ext+other_repo/ExternalLib.java:ExternalLib.java", + ]).in_order() + +def java_common_tests(name): + test_suite( + name = name, + tests = [ + _test_java_common_pack_sources_with_external_resource, + ], + ) diff --git a/test/java/bazel/common/java_info_tests.bzl b/test/java/bazel/common/java_info_tests.bzl new file mode 100644 index 00000000..cae1a922 --- /dev/null +++ b/test/java/bazel/common/java_info_tests.bzl @@ -0,0 +1,67 @@ +"""Tests for Bazel JavaInfo.""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_library.bzl", "java_library") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") + +# We can't transition on a Starlark-semantics affecting flag, so this relies on +# --incompatible_java_info_merge_runtime_module_flags set in .bazelrc +def _test_create_java_info_with_module_flags_merge_runtime(name): + util.helper_target( + custom_java_info_rule, + name = name + "/my_starlark_rule", + output_jar = name + "/doesnotmatter.jar", + dep = [name + "/dep"], + dep_runtime = [name + "/runtime"], + dep_exports = [name + "/export"], + add_exports = ["java.base/java.lang.invoke"], + ) + util.helper_target( + java_library, + name = name + "/dep", + srcs = ["java/A.java"], + add_exports = ["java.base/java.lang"], + add_opens = ["java.base/java.lang"], + ) + + util.helper_target( + java_library, + name = name + "/runtime", + srcs = ["java/A.java"], + add_opens = ["java.base/java.util"], + ) + + util.helper_target( + java_library, + name = name + "/export", + srcs = ["java/A.java"], + add_opens = ["java.base/java.math"], + ) + + analysis_test( + name = name, + impl = _test_create_java_info_with_module_flags_merge_runtime_impl, + target = name + "/my_starlark_rule", + ) + +def _test_create_java_info_with_module_flags_merge_runtime_impl(env, target): + assert_module_info = java_info_subject.from_target(env, target).module_flags() + assert_module_info.add_exports().contains_exactly([ + "java.base/java.lang", + "java.base/java.lang.invoke", + ]).in_order() + assert_module_info.add_opens().contains_exactly([ + "java.base/java.util", + "java.base/java.math", + "java.base/java.lang", + ]).in_order() + +def java_info_tests(name): + test_suite( + name = name, + tests = [ + _test_create_java_info_with_module_flags_merge_runtime, + ], + ) diff --git a/test/java/bazel/rules/BUILD.bazel b/test/java/bazel/rules/BUILD.bazel index 3bf8f436..6f97d15a 100644 --- a/test/java/bazel/rules/BUILD.bazel +++ b/test/java/bazel/rules/BUILD.bazel @@ -1,3 +1,12 @@ load(":java_binary_tests.bzl", "java_binary_tests") +load(":java_library_tests.bzl", "java_library_tests") +load(":java_plugin_tests.bzl", "java_plugin_tests") +load(":java_test_tests.bzl", "java_test_tests") java_binary_tests(name = "java_binary_tests") + +java_library_tests(name = "java_library_tests") + +java_plugin_tests(name = "java_plugin_tests") + +java_test_tests(name = "java_test_tests") diff --git a/test/java/bazel/rules/java_binary_tests.bzl b/test/java/bazel/rules/java_binary_tests.bzl index 32036d82..8c385046 100644 --- a/test/java/bazel/rules/java_binary_tests.bzl +++ b/test/java/bazel/rules/java_binary_tests.bzl @@ -3,6 +3,8 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") load("@rules_testing//lib:util.bzl", "util") load("//java:java_binary.bzl", "java_binary") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:rules/template_var_info_rule.bzl", "template_var_info_rule") def _test_java_binary_cross_compilation_to_unix(name): # A Unix platform that: @@ -46,10 +48,83 @@ def _test_java_binary_cross_compilation_to_unix_impl(env, target): assert_action.substitutions().keys().contains("%jvm_flags%") assert_action.inputs().contains_exactly(["java/bazel/rules/java_stub_template.txt"]) +def _test_java_binary_javacopts_make_variable_expansion(name): + util.helper_target( + template_var_info_rule, + name = name + "/vars", + vars = { + "MY_CUSTOM_OPT": "MY_OPT_VALUE", + }, + ) + util.helper_target( + java_binary, + name = name + "/bin", + srcs = ["java/A.java"], + javacopts = ["$(MY_CUSTOM_OPT)"], + toolchains = [name + "/vars"], + ) + + analysis_test( + name = name, + impl = _test_java_binary_javacopts_make_variable_expansion_impl, + target = name + "/bin", + # Broken by Starlarkification in the embedded rules in Bazel 7 + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_java_binary_javacopts_make_variable_expansion_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.compilation_info().javac_options().not_contains("$(MY_CUSTOM_OPT)") + assert_java_info.compilation_info().javac_options().contains("MY_OPT_VALUE") + +def _test_java_binary_javacopts_location_expansion(name): + util.helper_target( + java_binary, + name = name + "/bin", + srcs = ["A.java"], + javacopts = ["-XepOpt:foo=$(location :A.java)"], + ) + + analysis_test( + name = name, + impl = _test_java_binary_javacopts_location_expansion_impl, + target = name + "/bin", + ) + +def _test_java_binary_javacopts_location_expansion_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.compilation_info().javac_options().contains( + "-XepOpt:foo={package}/A.java", + ) + +def _test_java_binary_resource_strip_prefix(name): + util.helper_target( + java_binary, + name = name + "/bin", + srcs = ["Foo.java"], + main_class = "Foo", + resource_strip_prefix = native.package_name() + "/path/to/strip", + resources = ["path/to/strip/bar.props"], + ) + + analysis_test( + name = name, + impl = _test_java_binary_resource_strip_prefix_impl, + target = name + "/bin", + ) + +def _test_java_binary_resource_strip_prefix_impl(env, target): + env.expect.that_target(target).action_generating("{package}/{name}.jar").contains_flag_values([ + ("--resources", "{package}/path/to/strip/bar.props:bar.props"), + ]) + def java_binary_tests(name): test_suite( name = name, tests = [ _test_java_binary_cross_compilation_to_unix, + _test_java_binary_javacopts_make_variable_expansion, + _test_java_binary_javacopts_location_expansion, + _test_java_binary_resource_strip_prefix, ], ) diff --git a/test/java/bazel/rules/java_library_tests.bzl b/test/java/bazel/rules/java_library_tests.bzl new file mode 100644 index 00000000..770fbe60 --- /dev/null +++ b/test/java/bazel/rules/java_library_tests.bzl @@ -0,0 +1,44 @@ +"""Tests for the Bazel java_binary rule""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_library.bzl", "java_library") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:rules/template_var_info_rule.bzl", "template_var_info_rule") + +def _test_java_library_javacopts_make_variable_expansion(name): + util.helper_target( + template_var_info_rule, + name = name + "/vars", + vars = { + "MY_CUSTOM_OPT": "MY_OPT_VALUE", + }, + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["java/A.java"], + javacopts = ["$(MY_CUSTOM_OPT)"], + toolchains = [name + "/vars"], + ) + + analysis_test( + name = name, + impl = _test_java_library_javacopts_make_variable_expansion_impl, + target = name + "/lib", + # Broken by Starlarkification in the embedded rules in Bazel 7 + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_java_library_javacopts_make_variable_expansion_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.compilation_info().javac_options().not_contains("$(MY_CUSTOM_OPT)") + assert_java_info.compilation_info().javac_options().contains("MY_OPT_VALUE") + +def java_library_tests(name): + test_suite( + name = name, + tests = [ + _test_java_library_javacopts_make_variable_expansion, + ], + ) diff --git a/test/java/bazel/rules/java_plugin_tests.bzl b/test/java/bazel/rules/java_plugin_tests.bzl new file mode 100644 index 00000000..4df4bcca --- /dev/null +++ b/test/java/bazel/rules/java_plugin_tests.bzl @@ -0,0 +1,43 @@ +"""Tests for the Bazel java_binary rule""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_plugin.bzl", "java_plugin") +load("//test/java/testutil:rules/template_var_info_rule.bzl", "template_var_info_rule") + +def _test_java_plugin_javacopts_make_variable_expansion(name): + util.helper_target( + template_var_info_rule, + name = name + "/vars", + vars = { + "MY_CUSTOM_OPT": "MY_OPT_VALUE", + }, + ) + util.helper_target( + java_plugin, + name = name + "/plug", + srcs = ["java/A.java"], + javacopts = ["$(MY_CUSTOM_OPT)"], + toolchains = [name + "/vars"], + ) + + analysis_test( + name = name, + impl = _test_java_plugin_javacopts_make_variable_expansion_impl, + target = name + "/plug", + # Broken by Starlarkification in the embedded rules in Bazel 7 + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_java_plugin_javacopts_make_variable_expansion_impl(env, target): + assert_javac = env.expect.that_target(target).action_named("Javac") + assert_javac.not_contains_arg("$(MY_CUSTOM_OPT)") + assert_javac.contains_at_least_args(["MY_OPT_VALUE"]) + +def java_plugin_tests(name): + test_suite( + name = name, + tests = [ + _test_java_plugin_javacopts_make_variable_expansion, + ], + ) diff --git a/test/java/bazel/rules/java_test_tests.bzl b/test/java/bazel/rules/java_test_tests.bzl new file mode 100644 index 00000000..5c76b0ee --- /dev/null +++ b/test/java/bazel/rules/java_test_tests.bzl @@ -0,0 +1,59 @@ +"""Tests for the Bazel java_test rule""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching", "subjects") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_test.bzl", "java_test") + +def _test_deduced_test_class(name): + util.helper_target( + java_test, + name = name + "/foo", + srcs = [name + "/Foo.java"], + ) + + analysis_test( + name = name, + impl = _test_deduced_test_class_impl, + target = name + "/foo", + ) + +def _test_deduced_test_class_impl(env, target): + executable = target[DefaultInfo].files_to_run.executable.short_path + assert_action = env.expect.that_target(target).action_generating(executable) + + if assert_action.actual.substitutions: + # TemplateExpansion action on linux/mac + assert_jvm_flags = assert_action.substitutions().get( + "%jvm_flags%", + factory = lambda v, meta: subjects.collection([v], meta), + ) + else: + # Windows + assert_jvm_flags = assert_action.argv() + assert_jvm_flags.contains_predicate( + matching.str_matches("-Dbazel.test_suite=bazel.rules.test_deduced_test_class.foo"), + ) + +# regression test for https://github.com/bazelbuild/bazel/issues/20378 +def _test_invalid_test_class_at_repo_root(name): + analysis_test( + name = name, + impl = _test_invalid_test_class_at_repo_root_impl, + target = "//:invalid_test_at_repo_root", + expect_failure = True, + ) + +def _test_invalid_test_class_at_repo_root_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("cannot determine test class."), + ) + +def java_test_tests(name): + test_suite( + name = name, + tests = [ + _test_deduced_test_class, + _test_invalid_test_class_at_repo_root, + ], + ) diff --git a/test/java/common/java_common_tests.bzl b/test/java/common/java_common_tests.bzl index d4528df8..756e3a42 100644 --- a/test/java/common/java_common_tests.bzl +++ b/test/java/common/java_common_tests.bzl @@ -1,5 +1,8 @@ """Tests for java_common APIs""" +load("@bazel_features//:features.bzl", "bazel_features") +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") load("@rules_testing//lib:truth.bzl", "matching") load("@rules_testing//lib:util.bzl", "util") @@ -9,8 +12,10 @@ load("//java:java_plugin.bzl", "java_plugin") load("//java/common:java_common.bzl", "java_common") load("//java/common:java_info.bzl", "JavaInfo") load("//java/common:java_plugin_info.bzl", "JavaPluginInfo") +load("//java/toolchains:java_runtime.bzl", "java_runtime") load("//test/java/testutil:artifact_closure.bzl", "artifact_closure") load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:javac_action_subject.bzl", "javac_action_subject") load("//test/java/testutil:rules/custom_library.bzl", "custom_library") load("//test/java/testutil:rules/custom_library_extended_compile_jdeps.bzl", "CompileJdepsInfo", "custom_library_extended_jdeps") load("//test/java/testutil:rules/custom_library_with_additional_inputs.bzl", "custom_library_with_additional_inputs") @@ -20,7 +25,10 @@ load("//test/java/testutil:rules/custom_library_with_exports.bzl", "custom_libra load("//test/java/testutil:rules/custom_library_with_named_outputs.bzl", "custom_library_with_named_outputs") load("//test/java/testutil:rules/custom_library_with_sourcepaths.bzl", "custom_library_with_sourcepaths") load("//test/java/testutil:rules/custom_library_with_strict_deps.bzl", "custom_library_with_strict_deps") +load("//test/java/testutil:rules/custom_library_with_strict_java_deps_provider.bzl", "StrictJavaDepsInfo", "custom_library_with_strict_java_deps_provider") +load("//test/java/testutil:rules/custom_library_with_wrong_java_toolchain_type.bzl", "custom_library_with_wrong_java_toolchain_type") load("//test/java/testutil:rules/custom_library_with_wrong_plugins_type.bzl", "custom_library_with_wrong_plugins_type") +load("//test/java/testutil:rules/private_api_usage.bzl", "private_compile_api_usage", "private_merge_api_usage", "private_run_ijar_api_usage") def _test_compile_default_values(name): util.helper_target(custom_library, name = name + "/custom", srcs = ["Main.java"]) @@ -91,8 +99,6 @@ def _test_compile_exports_with_sources(name): name = name, impl = _test_compile_exports_with_sources_impl, target = target_name, - # Bazel 6 JavaInfo doesn't expose compile_time_java_dependencies - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_compile_exports_with_sources_impl(env, target): @@ -138,7 +144,6 @@ def _test_compile_extend_compile_time_jdeps(name): name = name, impl = _test_compile_extend_compile_time_jdeps_impl, target = name + "/foo", - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_compile_extend_compile_time_jdeps_impl(env, target): @@ -181,7 +186,6 @@ def _test_compile_extend_compile_time_jdeps_rule_outputs(name): "bar": name + "/bar", "baz": name + "/baz", }, - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_compile_extend_compile_time_jdeps_rule_outputs_impl(env, targets): @@ -234,7 +238,6 @@ def _test_compile_bootclasspath(name): name = name, impl = _test_compile_bootclasspath_impl, target = name + "/custom", - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_compile_bootclasspath_impl(env, target): @@ -269,7 +272,6 @@ def _test_compile_override_with_empty_bootclasspath(name): name = name, impl = _test_compile_override_with_empty_bootclasspath_impl, target = name + "/custom", - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_compile_override_with_empty_bootclasspath_impl(env, target): @@ -794,6 +796,328 @@ def _test_compile_strict_deps_enum_impl(env, target): matching.str_matches("invalid value for strict_deps: FOO"), ) +def _test_java_library_collects_coverage_dependencies_from_resources(name): + util.helper_target( + cc_binary, + name = name + "/lib/jni.so", + srcs = [name + "/lib/jni.cc"], + linkshared = 1, + features = ["-supports_pic"], + ) + util.helper_target( + java_library, + name = name + "/lib", + resources = [name + "/lib/jni.so"], + ) + + analysis_test( + name = name, + impl = _test_java_library_collects_coverage_dependencies_from_resources_impl, + target = name + "/lib", + config_settings = { + "//command_line_option:collect_code_coverage": "true", + "//command_line_option:instrumentation_filter": "//test/...", + }, + ) + +def _test_java_library_collects_coverage_dependencies_from_resources_impl(env, target): + env.expect.that_target(target).provider( + InstrumentedFilesInfo, + ).instrumented_files().contains_exactly(["{package}/{name}/jni.cc"]) + + env.expect.that_target(target).provider( + InstrumentedFilesInfo, + ).metadata_files().contains_exactly(["{package}/_objs/{name}/jni.so/jni.gcno"]) + +def _test_skip_annotation_processing(name): + util.helper_target( + java_plugin, + name = name + "/processor", + srcs = [name + "/processor.java"], + data = [name + "/processor_data.txt"], + generates_api = True, # so Turbine would normally run it + processor_class = "Foo", + ) + util.helper_target( + java_library, + name = name + "/exports_processor", + exported_plugins = [":" + name + "/processor"], + ) + util.helper_target( + custom_library, + name = name + "/custom", + srcs = [name + "/custom.java"], + plugins = [":" + name + "/processor"], + deps = [":" + name + "/exports_processor"], + enable_annotation_processing = False, + ) + util.helper_target( + java_library, + name = name + "/custom_noproc", + srcs = [name + "/custom.java"], + ) + + analysis_test( + name = name, + impl = _test_skip_annotation_processing_impl, + targets = { + "custom": ":" + name + "/custom", + "custom_noproc": ":" + name + "/custom_noproc", + }, + ) + +def _test_skip_annotation_processing_impl(env, targets): + javac_action = javac_action_subject.of(env, targets.custom, "{package}/lib{name}.jar") + + javac_action.mnemonic().equals("Javac") + javac_action.argv().not_contains("--processors") + javac_action.argv().contains("--processorpath") + javac_action.inputs().contains_at_least_predicates([ + matching.file_basename_equals("processor_data.txt"), + ]) + + turbine_action = javac_action_subject.of(env, targets.custom, "{package}/lib{name}-hjar.jar") + turbine_action.mnemonic().equals("JavacTurbine") + turbine_action.argv().not_contains("--processors") + + turbine_action_noproc = javac_action_subject.of(env, targets.custom_noproc, "{package}/lib{name}-hjar.jar") + turbine_action_noproc.mnemonic().equals("Turbine") + turbine_action_noproc.argv().not_contains("--processors") + +def _test_compile_direct_native_libraries(name): + target_name = name + "/custom" + util.helper_target( + cc_library, + name = target_name + "/native.so", + srcs = ["a.cc"], + ) + util.helper_target( + custom_library, + name = target_name, + srcs = ["A.java"], + ccdeps = [target_name + "/native.so"], + ) + + analysis_test( + name = name, + impl = _test_compile_direct_native_libraries_impl, + target = target_name, + ) + +def _test_compile_direct_native_libraries_impl(env, target): + assert_native_libs = java_info_subject.from_target(env, target).transitive_native_libraries() + assert_native_libs.static_libraries().contains_exactly_predicates([ + matching.any( + matching.str_matches("libnative.so.a"), # linux / mac + matching.str_matches("native.so.lib"), # windows + ), + ]) + +def _test_strict_java_deps_default(name): + util.helper_target( + custom_library, + name = name + "/unused", + ) + analysis_test( + name = name, + target = name + "/unused", # analysis_test requires setting a target. + impl = _test_strict_java_deps_default_impl, + fragments = ["java"], + ) + +def _test_strict_java_deps_default_impl(env, _unused): + env.expect.that_str(env.ctx.fragments.java.strict_java_deps).equals("default") + +def _test_strict_java_deps_error(name): + util.helper_target( + custom_library_with_strict_java_deps_provider, + name = name + "_strict_java_deps_provider", + ) + + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + analysis_test( + name = name, + impl = lambda env, target: env.expect.that_bool(True).equals(True), + target = name + "_strict_java_deps_provider", + ) + else: + analysis_test( + name = name, + target = name + "_strict_java_deps_provider", + impl = _test_strict_java_deps_error_impl, + fragments = ["java"], + config_settings = {"//command_line_option:experimental_strict_java_deps": "error"}, + ) + +def _test_strict_java_deps_error_impl(env, target): + env.expect.that_str(target[StrictJavaDepsInfo].strict_java_deps).equals("error") + +def _test_compile_output_jar_has_manifest_proto(name): + util.helper_target( + custom_library, + name = name + "/custom", + srcs = ["Main.java"], + ) + + analysis_test( + name = name, + impl = _test_compile_output_jar_has_manifest_proto_impl, + target = name + "/custom", + ) + +def _test_compile_output_jar_has_manifest_proto_impl(env, target): + java_info_subject.from_target(env, target).java_outputs().singleton().manifest_proto().short_path_equals( + "{package}/lib{name}.jar_manifest_proto", + ) + +def _test_compile_with_neverlink_deps(name): + target_name = name + "/custom" + util.helper_target( + java_library, + name = target_name + "/neverlink_dep", + srcs = ["B.java"], + neverlink = True, + ) + util.helper_target( + custom_library, + name = target_name, + srcs = ["A.java"], + deps = [target_name + "/neverlink_dep"], + ) + + analysis_test( + name = name, + impl = _test_compile_with_neverlink_deps_impl, + target = target_name, + ) + +def _test_compile_with_neverlink_deps_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.compilation_args().transitive_runtime_jars().contains_exactly([ + "{package}/lib{name}.jar", + ]) + assert_java_info.transitive_source_jars().contains_exactly([ + "{package}/lib{name}-src.jar", + "{package}/lib{name}/neverlink_dep-src.jar", + ]) + assert_java_info.compilation_args().transitive_compile_time_jars().contains_exactly([ + "{package}/lib{name}-hjar.jar", + "{package}/lib{name}/neverlink_dep-hjar.jar", + ]) + +def _test_compile_output_jar_not_in_runtime_path_without_sources_defined(name): + target_name = name + "/custom" + util.helper_target( + java_library, + name = target_name + "/export_dep", + srcs = ["B.java"], + ) + util.helper_target( + custom_library, + name = target_name, + srcs = [], + exports = [target_name + "/export_dep"], + ) + + analysis_test( + name = name, + impl = _test_compile_output_jar_not_in_runtime_path_without_sources_defined_impl, + target = target_name, + ) + +def _test_compile_output_jar_not_in_runtime_path_without_sources_defined_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.compilation_args().transitive_runtime_jars().contains_exactly([ + "{package}/lib{name}/export_dep.jar", + ]) + assert_java_info.compilation_args().transitive_compile_time_jars().contains_exactly([ + "{package}/lib{name}/export_dep-hjar.jar", + ]) + assert_java_info.java_outputs().singleton().class_jar().short_path_equals("{package}/lib{name}.jar") + assert_java_info.java_outputs().singleton().compile_jar().equals(None) + +def _test_java_runtime_provider_files(name): + # Create a rule that extracts JavaRuntimeInfo.files + util.helper_target( + java_runtime, + name = name + "/jvm", + srcs = ["a.txt"], + java_home = "foo/bar", + ) + + analysis_test( + name = name, + impl = _test_java_runtime_provider_files_impl, + target = name + "/jvm", + ) + +def _test_java_runtime_provider_files_impl(env, target): + env.expect.that_target(target).default_outputs().contains_exactly(["{package}/a.txt"]) + +def _test_custom_library_with_wrong_java_toolchain_type(name): + util.helper_target( + custom_library_with_wrong_java_toolchain_type, + name = name + "/custom", + srcs = ["a.java"], + ) + analysis_test( + name = name, + impl = _test_custom_library_with_wrong_java_toolchain_type_impl, + target = name + "/custom", + expect_failure = True, + ) + +def _test_custom_library_with_wrong_java_toolchain_type_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("got element of type ToolchainInfo, want JavaToolchainInfo"), + ) + +def _test_private_api(name, helper_rule, private_attr_name): + util.helper_target( + helper_rule, + name = name + "/custom", + private_attr_name = private_attr_name, + ) + + analysis_test( + name = name, + impl = lambda env, target: _test_private_api_impl(env, target, private_attr_name), + target = name + "/custom", + expect_failure = True, + ) + +def _test_private_api_impl(env, target, private_attr_name): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("got unexpected keyword argument: " + private_attr_name), + ) + +def _test_compile_disabling_compile_jar_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "enable_compile_jar_action") + +def _test_compile_classpath_resources_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "classpath_resources") + +def _test_compile_injecting_rule_kind_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "injecting_rule_kind") + +def _test_compile_enable_jspecify_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "enable_jspecify") + +def _test_merge_java_outputs_is_private_api(name): + _test_private_api(name, private_merge_api_usage, "merge_java_outputs") + +def _test_merge_source_jars_is_private_api(name): + _test_private_api(name, private_merge_api_usage, "merge_source_jars") + +def _test_compile_include_compilation_info_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "include_compilation_info") + +def _test_compile_resource_jars_is_private_api(name): + _test_private_api(name, private_compile_api_usage, "resource_jars") + +def _test_run_ijar_output_is_private_api(name): + _test_private_api(name, private_run_ijar_api_usage, "output") + def java_common_tests(name): test_suite( name = name, @@ -823,5 +1147,24 @@ def java_common_tests(name): _test_compile_neverlink, _test_compile_strict_deps_case_sensitivity, _test_compile_strict_deps_enum, + _test_java_library_collects_coverage_dependencies_from_resources, + _test_skip_annotation_processing, + _test_compile_direct_native_libraries, + _test_strict_java_deps_default, + _test_strict_java_deps_error, + _test_compile_output_jar_has_manifest_proto, + _test_compile_with_neverlink_deps, + _test_compile_output_jar_not_in_runtime_path_without_sources_defined, + _test_java_runtime_provider_files, + _test_custom_library_with_wrong_java_toolchain_type, + _test_compile_disabling_compile_jar_is_private_api, + _test_compile_classpath_resources_is_private_api, + _test_compile_injecting_rule_kind_is_private_api, + _test_compile_enable_jspecify_is_private_api, + _test_merge_java_outputs_is_private_api, + _test_merge_source_jars_is_private_api, + _test_compile_include_compilation_info_is_private_api, + _test_compile_resource_jars_is_private_api, + _test_run_ijar_output_is_private_api, ], ) diff --git a/test/java/common/java_info_tests.bzl b/test/java/common/java_info_tests.bzl index 5d3c6663..daea0485 100644 --- a/test/java/common/java_info_tests.bzl +++ b/test/java/common/java_info_tests.bzl @@ -10,7 +10,9 @@ load("//java/common:java_info.bzl", "JavaInfo") load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") load("//test/java/testutil:rules/bad_java_info_rules.bzl", "bad_deps", "bad_exports", "bad_libs", "bad_runtime_deps", "compile_jar_not_set", "compile_jar_set_to_none") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") +load("//test/java/testutil:rules/custom_library.bzl", "custom_library") load("//test/java/testutil:rules/forward_java_info.bzl", "java_info_forwarding_rule") +load("//test/java/testutil:rules/java_info_merge.bzl", "java_info_merge_rule") def _with_output_jar_only_test(name): target_name = name + "/my_starlark_rule" @@ -168,8 +170,6 @@ def _with_native_libraries_test(name): name = name, impl = _with_native_libraries_test_impl, target = target_name, - # LibraryToLink.library_indentifier only available from Bazel 8 - attr_values = {"tags": ["min_bazel_8"]}, ) def _with_native_libraries_test_impl(env, target): @@ -1255,13 +1255,169 @@ def _output_source_jars_returns_depset_test(name): name = name, impl = _output_source_jars_returns_depset_test_impl, target = target_name, - attr_values = {"tags": ["min_bazel_7"]}, # changed in Bazel 7 ) def _output_source_jars_returns_depset_test_impl(env, target): source_jars = target[JavaInfo].java_outputs[0].source_jars env.expect.that_str(type(source_jars)).equals(type(depset())) +def _java_info_constructor_with_neverlink_test(name): + target_name = name + "/my_starlark_rule" + util.helper_target( + custom_java_info_rule, + name = target_name, + output_jar = target_name + "/my_starlark_rule_lib.jar", + neverlink = True, + ) + + analysis_test( + name = name, + impl = _java_info_constructor_with_neverlink_test_impl, + target = target_name, + ) + +def _java_info_constructor_with_neverlink_test_impl(env, target): + java_info_subject.from_target(env, target).is_neverlink().equals(True) + +def _java_common_merge_with_neverlink_test(name): + target_name = name + "/merged" + util.helper_target( + custom_java_info_rule, + name = target_name + "/with_neverlink", + output_jar = target_name + "/with_neverlink.jar", + neverlink = True, + ) + util.helper_target( + custom_java_info_rule, + name = target_name + "/without_neverlink", + output_jar = target_name + "/without_neverlink.jar", + neverlink = False, + ) + util.helper_target( + java_info_merge_rule, + name = target_name, + deps = [target_name + "/with_neverlink", target_name + "/without_neverlink"], + ) + + analysis_test( + name = name, + impl = _java_common_merge_with_neverlink_test_impl, + target = target_name, + ) + +def _java_common_merge_with_neverlink_test_impl(env, target): + java_info_subject.from_target(env, target).is_neverlink().equals(True) + +def _java_common_compile_with_neverlink_test(name): + target_name = name + "/compiled" + util.helper_target( + custom_library, + name = target_name, + srcs = ["A.java"], + neverlink = True, + ) + + analysis_test( + name = name, + impl = _java_common_compile_with_neverlink_test_impl, + target = target_name, + ) + +def _java_common_compile_with_neverlink_test_impl(env, target): + java_info_subject.from_target(env, target).is_neverlink().equals(True) + +# Tests that java_common.compile propagates native libraries from deps, +# runtime_deps, and exports. +def _java_common_compile_native_libraries_propagate_test(name): + target_name = name + "/compiled" + + util.helper_target( + cc_library, + name = target_name + "/native_dep", + srcs = ["a.cc"], + ) + util.helper_target( + java_library, + name = target_name + "/lib_dep", + srcs = ["B.java"], + deps = [target_name + "/native_dep"], + ) + + util.helper_target( + cc_library, + name = target_name + "/native_rdep", + srcs = ["c.cc"], + ) + util.helper_target( + java_library, + name = target_name + "/lib_rdep", + srcs = ["D.java"], + deps = [target_name + "/native_rdep"], + ) + + util.helper_target( + cc_library, + name = target_name + "/native_export", + srcs = ["e.cc"], + ) + util.helper_target( + java_library, + name = target_name + "/lib_export", + srcs = ["F.java"], + deps = [target_name + "/native_export"], + ) + + util.helper_target( + custom_library, + name = target_name, + srcs = ["G.java"], + deps = [target_name + "/lib_dep"], + runtime_deps = [target_name + "/lib_rdep"], + exports = [target_name + "/lib_export"], + ) + + analysis_test( + name = name, + impl = _java_common_compile_native_libraries_propagate_test_impl, + target = target_name, + ) + +def _java_common_compile_native_libraries_propagate_test_impl(env, target): + assert_native_libs = java_info_subject.from_target(env, target).transitive_native_libraries() + assert_native_libs.static_libraries().contains_exactly_predicates([ + matching.str_matches("*native_rdep*"), + matching.str_matches("*native_export*"), + matching.str_matches("*native_dep*"), + ]) + +def _test_merge_runtime_output_jars(name): + util.helper_target( + java_library, + name = name + "/a", + srcs = ["A.java"], + ) + util.helper_target( + java_library, + name = name + "/b", + srcs = ["B.java"], + ) + util.helper_target( + java_info_merge_rule, + name = name + "/merged", + deps = [name + "/a", name + "/b"], + ) + analysis_test( + name = name, + impl = _test_merge_runtime_output_jars_impl, + target = name + "/merged", + ) + +def _test_merge_runtime_output_jars_impl(env, target): + java_info_subject.from_target(env, target).runtime_output_jars().contains_exactly([ + "{package}/lib{test_name}/a.jar", + "{package}/lib{test_name}/b.jar", + ]) + def java_info_tests(name): test_suite( name = name, @@ -1306,5 +1462,10 @@ def java_info_tests(name): _annotation_processing_test, _compilation_info_test, _output_source_jars_returns_depset_test, + _java_info_constructor_with_neverlink_test, + _java_common_merge_with_neverlink_test, + _java_common_compile_with_neverlink_test, + _java_common_compile_native_libraries_propagate_test, + _test_merge_runtime_output_jars, ], ) diff --git a/test/java/common/java_plugin_info_tests.bzl b/test/java/common/java_plugin_info_tests.bzl index c3b8b378..ed742f13 100644 --- a/test/java/common/java_plugin_info_tests.bzl +++ b/test/java/common/java_plugin_info_tests.bzl @@ -124,7 +124,6 @@ def _test_without_processor_class(name): name = name, impl = _test_without_processor_class_impl, target = target_name, - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_without_processor_class_impl(env, target): diff --git a/test/java/common/rules/BUILD b/test/java/common/rules/BUILD index 2311a3f2..97589249 100644 --- a/test/java/common/rules/BUILD +++ b/test/java/common/rules/BUILD @@ -1,20 +1,59 @@ +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_library.bzl", "java_library") +load(":add_exports_tests.bzl", "add_exports_tests") +load(":common_launcher_java_binary_tests.bzl", "java_binary_launcher_tests") +load(":common_launcher_java_library_tests.bzl", "java_library_launcher_tests") +load(":deploy_archive_builder_tests.bzl", "deploy_archive_builder_test_suite") load(":java_binary_tests.bzl", "java_binary_tests") load(":java_import_tests.bzl", "java_import_tests") +load(":java_launcher_tests.bzl", "java_launcher_tests") load(":java_library_tests.bzl", "java_library_tests") load(":java_plugin_tests.bzl", "java_plugin_tests") +load(":java_single_jar_tests.bzl", "java_single_jar_tests") load(":java_test_tests.bzl", "java_test_tests") load(":merge_attrs_tests.bzl", "merge_attrs_test_suite") package(default_applicable_licenses = ["@rules_java//:license"]) +deploy_archive_builder_test_suite(name = "deploy_archive_builder_tests") + merge_attrs_test_suite(name = "merge_attrs_tests") java_binary_tests(name = "java_binary_tests") +java_binary_launcher_tests(name = "java_binary_launcher_tests") + java_plugin_tests(name = "java_plugin_tests") java_library_tests(name = "java_library_tests") +java_library_launcher_tests(name = "java_library_launcher_tests") + +java_launcher_tests(name = "java_launcher_tests") + java_import_tests(name = "java_import_tests") +java_single_jar_tests(name = "java_single_jar_tests") + java_test_tests(name = "java_test_tests") + +add_exports_tests(name = "add_exports_tests") + +# Used for tests. +util.helper_target( + java_library, + name = "module_javacopts_helper", + srcs = [ + "InputFile.java", + "InputFile2.java", + ], + add_exports = [ + "export/one", + "export/two", + ], + add_opens = [ + "open/one", + "open/two", + ], + visibility = ["//test/java:__subpackages__"], +) diff --git a/test/java/common/rules/add_exports_tests.bzl b/test/java/common/rules/add_exports_tests.bzl new file mode 100644 index 00000000..482e7311 --- /dev/null +++ b/test/java/common/rules/add_exports_tests.bzl @@ -0,0 +1,39 @@ +"""Tests for the add_exports attribute""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:defs.bzl", "java_library") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:rules/java_info_merge.bzl", "java_info_merge_rule") + +def _test_merge_add_exports(name): + util.helper_target( + java_info_merge_rule, + name = name + "/merge", + deps = [name + "/a"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["A.java"], + add_exports = ["java.base/java.lang"], + ) + + analysis_test( + name = name, + impl = _test_merge_add_exports_impl, + target = name + "/merge", + ) + +def _test_merge_add_exports_impl(env, target): + java_info_subject.from_target(env, target).module_flags().add_exports().contains_exactly( + ["java.base/java.lang"], + ) + +def add_exports_tests(name): + test_suite( + name = name, + tests = [ + _test_merge_add_exports, + ], + ) diff --git a/test/java/common/rules/common_launcher_java_binary_tests.bzl b/test/java/common/rules/common_launcher_java_binary_tests.bzl new file mode 100644 index 00000000..572f27a0 --- /dev/null +++ b/test/java/common/rules/common_launcher_java_binary_tests.bzl @@ -0,0 +1,32 @@ +"""Parameterized tests for java_binary with --java_launcher""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_binary.bzl", "java_binary") + +def _test_java_binary_non_executable_rule_outputs(name): + util.helper_target( + java_binary, + name = name + "/test_app_noexec", + srcs = ["InputFile.java"], + create_executable = 0, + ) + + analysis_test( + name = name, + impl = _test_java_binary_non_executable_rule_outputs_impl, + target = name + "/test_app_noexec", + ) + +def _test_java_binary_non_executable_rule_outputs_impl(env, target): + env.expect.that_target(target).default_outputs().contains_exactly([ + "{package}/{name}.jar", + ]) + +def java_binary_launcher_tests(name): + test_suite( + name = name, + tests = [ + _test_java_binary_non_executable_rule_outputs, + ], + ) diff --git a/test/java/common/rules/common_launcher_java_library_tests.bzl b/test/java/common/rules/common_launcher_java_library_tests.bzl new file mode 100644 index 00000000..c66256ec --- /dev/null +++ b/test/java/common/rules/common_launcher_java_library_tests.bzl @@ -0,0 +1,1134 @@ +"""Parameterized tests for java_library with --java_launcher""" + +load("@bazel_features//:features.bzl", "bazel_features") +load("@rules_cc//cc:cc_library.bzl", "cc_library") +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_import.bzl", "java_import") +load("//java:java_library.bzl", "java_library") +load("//java:java_plugin.bzl", "java_plugin") +load("//java/toolchains:java_runtime.bzl", "java_runtime") +load("//java/toolchains:java_toolchain.bzl", "java_toolchain") +load("//test/java/testutil:helper.bzl", "always_passes") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:javac_action_subject.bzl", "javac_action_subject") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_toolchain") +load("//test/java/testutil:rules/custom_library_with_bootclasspath.bzl", "custom_bootclasspath") + +def _test_java_library_rule_outputs(name): + util.helper_target( + java_library, + name = name + "/test_lib", + srcs = ["A.java"], + ) + + analysis_test( + name = name, + impl = _test_java_library_rule_outputs_impl, + target = name + "/test_lib", + ) + +def _test_java_library_rule_outputs_impl(env, target): + env.expect.that_target(target).default_outputs().contains_exactly([ + "{package}/lib{name}.jar", + ]) + +def _test_java_library_action_graph(name): + util.helper_target( + java_library, + name = name + "/test_lib", + srcs = [ + "Util.java", + "Util2.java", + ], + javacopts = [ + "-g", + "-encoding", + "utf8", + ], + ) + + analysis_test( + name = name, + impl = _test_java_library_action_graph_impl, + target = name + "/test_lib", + ) + +def _test_java_library_action_graph_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.inputs().contains_at_least([ + "{package}/Util.java", + "{package}/Util2.java", + ]) + javac_action.javacopts().contains_at_least([ + "-g", + "-encoding", + "utf8", + ]) + +def _test_java_library_deps_of_genrule_are_not_on_classpath(name): + util.helper_target( + java_library, + name = name + "/root_dep", + srcs = ["test.java"], + ) + util.helper_target( + native.genrule, + name = name + "/has_java_dep", + outs = [name + "_foo.jar"], + cmd = "echo NOT EXECUTED", + tools = [name + "/root_dep"], + ) + util.helper_target( + java_import, + name = name + "/has_java_dep_import", + jars = [name + "/has_java_dep"], + ) + util.helper_target( + java_library, + name = name + "/library", + srcs = ["dummy.java"], + deps = [name + "/has_java_dep_import"], + ) + + analysis_test( + name = name, + impl = _test_java_library_deps_of_genrule_are_not_on_classpath_impl, + target = name + "/library", + ) + +def _test_java_library_deps_of_genrule_are_not_on_classpath_impl(env, target): + expected_classpath = "{bin_path}/{package}/_ijar/{test_name}/has_java_dep_import/{package}/{test_name}_foo-ijar.jar" + javac_action_subject.of(env, target, "{package}/lib{name}.jar").classpath().contains_exactly([expected_classpath]) + +def _test_java_library_compile_and_run_time_paths(name): + util.helper_target( + java_library, + name = name + "/base", + srcs = ["Base.java"], + ) + util.helper_target( + java_library, + name = name + "/specialization", + srcs = ["Specialization.java"], + deps = [name + "/base"], + ) + + analysis_test( + name = name, + impl = _test_java_library_compile_and_run_time_paths_impl, + targets = { + "base": name + "/base", + "specialization": name + "/specialization", + }, + ) + +def _test_java_library_compile_and_run_time_paths_impl(env, targets): + base_info = java_info_subject.from_target(env, targets.base) + base_info.compilation_args().transitive_runtime_jars().contains_exactly(["{package}/lib{name}.jar"]) + base_info.compilation_args().transitive_compile_time_jars().contains_exactly(["{package}/lib{name}-hjar.jar"]) + base_info.compilation_args().compile_jars().contains_exactly(["{package}/lib{name}-hjar.jar"]) + + base_jar = "{package}/lib{test_name}/base.jar" + base_hjar = "{package}/lib{test_name}/base-hjar.jar" + + specialization_info = java_info_subject.from_target(env, targets.specialization) + specialization_info.compilation_args().transitive_runtime_jars().contains_exactly([ + base_jar, + "{package}/lib{name}.jar", + ]) + specialization_info.compilation_args().transitive_compile_time_jars().contains_exactly([ + base_hjar, + "{package}/lib{name}-hjar.jar", + ]) + specialization_info.compilation_args().compile_jars().contains_exactly(["{package}/lib{name}-hjar.jar"]) + +def _test_java_library_files_to_compile(name): + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["Lib.java"], + ) + + analysis_test( + name = name, + impl = _test_java_library_files_to_compile_impl, + target = name + "/lib", + ) + +def _test_java_library_files_to_compile_impl(env, target): + env.expect.that_target(target).output_group("compilation_outputs").contains_exactly(["{package}/lib{name}.jar"]) + +def _test_java_library_runtime_deps_are_not_on_classpath(name): + util.helper_target( + java_library, + name = name + "/runtime_java_dep", + srcs = ["test.java"], + ) + util.helper_target( + java_library, + name = name + "/compile_dep", + srcs = ["compile.java"], + ) + util.helper_target( + java_library, + name = name + "/depends_on_runtimedep", + srcs = ["dummy.java"], + runtime_deps = [name + "/runtime_java_dep"], + deps = [name + "/compile_dep"], + ) + + analysis_test( + name = name, + impl = _test_java_library_runtime_deps_are_not_on_classpath_impl, + target = name + "/depends_on_runtimedep", + ) + +def _test_java_library_runtime_deps_are_not_on_classpath_impl(env, target): + expected_compile = "{bin_path}/{package}/lib{test_name}/compile_dep-hjar.jar" + javac_action_subject.of(env, target, "{package}/lib{name}.jar").classpath().contains_exactly([expected_compile]) + +def _test_java_library_runtime_deps_are_not_on_classpath_with_header_compilation(name): + util.helper_target( + java_library, + name = name + "/runtime_java_dep", + srcs = ["test.java"], + ) + util.helper_target( + java_library, + name = name + "/compile_dep", + srcs = ["compile.java"], + ) + util.helper_target( + java_library, + name = name + "/depends_on_runtimedep", + srcs = ["dummy.java"], + runtime_deps = [name + "/runtime_java_dep"], + deps = [name + "/compile_dep"], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:java_header_compilation": True, + }, + impl = _test_java_library_runtime_deps_are_not_on_classpath_with_header_compilation_impl, + target = name + "/depends_on_runtimedep", + ) + +def _test_java_library_runtime_deps_are_not_on_classpath_with_header_compilation_impl(env, target): + expected_compile = "{bin_path}/{package}/lib{test_name}/compile_dep-hjar.jar" + javac_action_subject.of(env, target, "{package}/lib{name}.jar").classpath().contains_exactly([expected_compile]) + +def _test_java_library_annotation_processing_using_javacopt(name): + util.helper_target( + java_library, + name = name + "/to_be_processed", + srcs = ["ToBeProcessed.java"], + javacopts = ["-processor com.google.process.Processor"], + ) + + analysis_test( + name = name, + impl = _test_java_library_annotation_processing_using_javacopt_impl, + target = name + "/to_be_processed", + ) + +def _test_java_library_annotation_processing_using_javacopt_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.argv().contains("--generated_sources_output") + javac_action.generated_sources_output().contains("{bin_path}/{package}/lib{name}-gensrc.jar") + javac_action.javacopts().contains("-processor") + javac_action.javacopts().contains("com.google.process.Processor") + + # The compile action should have a gensrc jar output + javac_action.outputs().contains("{package}/lib{name}-gensrc.jar") + + # The gensrc jar should be an input to the source jar action + src_jar_action = env.expect.that_target(target).action_generating("{package}/lib{name}-src.jar") + src_jar_action.inputs().contains("{package}/lib{name}-gensrc.jar") + +def _test_java_library_javacopts_with_location_expansion(name): + util.helper_target( + java_library, + name = name + "/patch", + srcs = ["A.java"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["ToBeProcessed.java"], + javacopts = ["--patch $(execpath " + name + "/patch)"], + deps = [name + "/patch"], + ) + + analysis_test( + name = name, + impl = _test_java_library_javacopts_with_location_expansion_impl, + target = name + "/lib", + ) + +def _test_java_library_javacopts_with_location_expansion_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.javacopts().contains_at_least([ + "--patch", + "{bin_path}/{package}/lib{test_name}/patch.jar", + ]) + +def _test_java_library_invalid_plugin(name): + util.helper_target( + java_library, + name = name + "/not_a_plugin", + srcs = ["NotAPlugin.java"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["Lib.java"], + plugins = [name + "/not_a_plugin"], + ) + + analysis_test( + name = name, + expect_failure = True, + impl = _test_java_library_invalid_plugin_impl, + target = name + "/lib", + ) + +def _test_java_library_invalid_plugin_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("does not have mandatory providers: 'JavaPluginInfo'"), + ) + +def _test_java_library_plugin_with_runtime_deps(name): + util.helper_target( + java_library, + name = name + "/runtime_lib", + srcs = ["Runtime.java"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["Lib.java"], + runtime_deps = [name + "/runtime_lib"], + ) + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + processor_class = "com.example.process.stuff", + deps = [name + "/lib"], + ) + util.helper_target( + java_library, + name = name + "/leaf_lib", + srcs = ["LeafLib.java"], + plugins = [name + "/plugin"], + ) + + analysis_test( + name = name, + impl = _test_java_library_plugin_with_runtime_deps_impl, + target = name + "/leaf_lib", + ) + +def _test_java_library_plugin_with_runtime_deps_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.processorpath().contains_exactly_predicates([ + matching.str_matches("*/plugin.jar"), + matching.str_matches("*/lib.jar"), + matching.str_matches("*/runtime_lib.jar"), + ]) + +def _test_java_library_source_jar_without_annotation_processing(name): + util.helper_target( + java_library, + name = name + "/foo", + srcs = ["Foo.java"], + ) + + analysis_test( + name = name, + impl = _test_java_library_source_jar_without_annotation_processing_impl, + target = name + "/foo", + ) + +def _test_java_library_source_jar_without_annotation_processing_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.argv().not_contains("--generated_sources_output") + javac_action.outputs().contains_exactly([ + "{package}/lib{name}.jar", + "{package}/lib{name}.jdeps", + "{package}/lib{name}-native-header.jar", + "{package}/lib{name}.jar_manifest_proto", + ]) + + src_jar_action = javac_action_subject.of(env, target, "{package}/lib{name}-src.jar") + src_jar_action.outputs().contains_exactly([ + "{package}/lib{name}-src.jar", + ]) + +def _test_java_library_source_jars_with_source_jars(name): + util.helper_target( + java_library, + name = name + "/beatit", + srcs = [ + "Plugin.java", + "Some.srcjar", + ], + ) + + analysis_test( + name = name, + impl = _test_java_library_source_jars_with_source_jars_impl, + target = name + "/beatit", + ) + +def _test_java_library_source_jars_with_source_jars_impl(env, target): + src_jar_action = javac_action_subject.of(env, target, "{package}/lib{name}-src.jar") + src_jar_action.inputs().contains_at_least([ + "{package}/Plugin.java", + "{package}/Some.srcjar", + ]) + src_jar_action.sources().contains_exactly([ + "{package}/Some.srcjar", + ]) + src_jar_action.resources().contains_predicate( + matching.str_matches("*/Plugin.java:*rules/Plugin.java"), + ) + +def _test_java_library_should_set_bootclasspath(name): + boot_jar = util.empty_file(name + "/boot.jar") + util.helper_target( + custom_bootclasspath, + name = name + "/mock_bootclasspath", + bootclasspath = [boot_jar], + ) + + util.helper_target( + java_runtime, + name = name + "/runtime", + ) + + util.helper_target( + java_toolchain, + name = name + "/mock_toolchain_impl", + bootclasspath = [name + "/mock_bootclasspath"], + genclass = name + "/genclass", + header_compiler = name + "/header_compiler", + header_compiler_direct = name + "/header_compiler_direct", + ijar = name + "/ijar", + java_runtime = name + "/runtime", + javabuilder = name + "/javabuilder", + singlejar = name + "/singlejar", + ) + util.helper_target( + native.toolchain, + name = name + "/toolchain", + toolchain = name + "/mock_toolchain_impl", + toolchain_type = "@bazel_tools//tools/jdk:toolchain_type", + ) + util.helper_target( + java_library, + name = name + "/test_lib", + srcs = ["A.java"], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:extra_toolchains": [ + native.package_relative_label(name + "/toolchain"), + ], + }, + impl = _test_java_library_should_set_bootclasspath_impl, + target = name + "/test_lib", + ) + +def _test_java_library_should_set_bootclasspath_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + + javac_action.bootclasspath().contains_exactly([ + "{bin_path}/{package}/{test_name}/boot.jar", + ]) + +def _test_java_library_command_line_contains_target_label_and_rule_kind(name): + util.helper_target( + java_library, + name = name + "/test_lib", + srcs = ["A.java"], + ) + + analysis_test( + name = name, + impl = _test_java_library_command_line_contains_target_label_and_rule_kind_impl, + target = name + "/test_lib", + ) + +def _test_java_library_command_line_contains_target_label_and_rule_kind_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.target_label().contains_exactly(["//{package}:{name}"]) + +def _test_java_library_propagates_native_libraries(name): + util.helper_target( + cc_library, + name = name + "/native_deps1.so", + srcs = ["a.cc"], + ) + util.helper_target( + java_library, + name = name + "/lib_deps", + srcs = ["B.java"], + deps = [name + "/native_deps1.so"], + ) + util.helper_target( + cc_library, + name = name + "/native_deps2.so", + srcs = ["b.cc"], + ) + util.helper_target( + cc_library, + name = name + "/native_rdeps1.so", + srcs = ["c.cc"], + ) + util.helper_target( + java_library, + name = name + "/lib_runtime_deps", + srcs = ["C.java"], + deps = [name + "/native_rdeps1.so"], + ) + util.helper_target( + cc_library, + name = name + "/native_rdeps2.so", + srcs = ["d.cc"], + ) + util.helper_target( + cc_library, + name = name + "/native_exports1.so", + srcs = ["e.cc"], + ) + util.helper_target( + java_library, + name = name + "/lib_exports", + srcs = ["D.java"], + deps = [name + "/native_exports1.so"], + ) + util.helper_target( + cc_library, + name = name + "/native_exports2.so", + srcs = ["f.cc"], + ) + util.helper_target( + cc_library, + name = name + "/native_data1.so", + srcs = ["g.cc"], + ) + util.helper_target( + java_library, + name = name + "/lib_data", + srcs = ["E.java"], + deps = [name + "/native_data1.so"], + ) + util.helper_target( + cc_library, + name = name + "/native_data2.so", + srcs = ["h.cc"], + ) + util.helper_target( + java_library, + name = name + "/top", + srcs = ["A.java"], + data = [ + name + "/lib_data", + name + "/native_data2.so", + ], + exports = [ + name + "/lib_exports", + name + "/native_exports2.so", + ], + runtime_deps = [ + name + "/lib_runtime_deps", + name + "/native_rdeps2.so", + ], + deps = [ + name + "/lib_deps", + name + "/native_deps2.so", + ], + ) + + analysis_test( + name = name, + impl = _test_java_library_propagates_native_libraries_impl, + target = name + "/top", + ) + +def _test_java_library_propagates_native_libraries_impl(env, target): + java_info_subject.from_target(env, target).transitive_native_libraries().static_libraries().contains_exactly_predicates([ + # Windows platforms use .lib extension for static libraries. + matching.is_in(["libnative_rdeps2.so.a", "native_rdeps2.so.lib"]), + matching.is_in(["libnative_exports2.so.a", "native_exports2.so.lib"]), + matching.is_in(["libnative_deps2.so.a", "native_deps2.so.lib"]), + matching.is_in(["libnative_rdeps1.so.a", "native_rdeps1.so.lib"]), + matching.is_in(["libnative_exports1.so.a", "native_exports1.so.lib"]), + matching.is_in(["libnative_deps1.so.a", "native_deps1.so.lib"]), + ]) + +def _test_java_library_gen_source_no_processor_names(name): + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["AnnotationProcessor.java"], + ) + util.helper_target( + java_library, + name = name + "/to_be_processed", + srcs = ["ToBeProcessed.java"], + plugins = [name + "/plugin"], + ) + + analysis_test( + name = name, + impl = _test_java_library_gen_source_no_processor_names_impl, + target = name + "/to_be_processed", + ) + +def _test_java_library_gen_source_no_processor_names_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + + # The compile action should not have a gensrc jar output even though it has a plugin, + # since the plugin doesn't define a processor. + javac_action.outputs().contains_exactly([ + "{package}/lib{name}.jar", + "{package}/lib{name}.jdeps", + "{package}/lib{name}-native-header.jar", + "{package}/lib{name}.jar_manifest_proto", + ]) + +def _test_java_library_compilation_info_provider(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + bootclasspath = [name + "/boot.jar"], + ) + + util.helper_target( + java_library, + name = name + "/test_lib", + srcs = ["A.java"], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:extra_toolchains": [ + native.package_relative_label(name + "/toolchain"), + ], + }, + impl = _test_java_library_compilation_info_provider_impl, + target = name + "/test_lib", + ) + +def _test_java_library_compilation_info_provider_impl(env, target): + java_info_subject.from_target(env, target).compilation_info().boot_classpath().contains_exactly([ + "{package}/{test_name}/boot.jar", + ]) + +def _test_java_library_native_header_outputs(name): + util.helper_target( + java_library, + name = name + "/jni", + srcs = [ + "Bar.java", + "Foo.java", + ], + ) + + analysis_test( + name = name, + impl = _test_java_library_native_header_outputs_impl, + target = name + "/jni", + ) + +def _test_java_library_native_header_outputs_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.native_header_output().contains_exactly([ + "{bin_path}/{package}/lib{name}-native-header.jar", + ]) + javac_action.outputs().contains("{package}/lib{name}-native-header.jar") + java_info_subject.from_target(env, target).outputs().native_headers().contains_exactly([ + "{package}/lib{name}-native-header.jar", + ]) + +def _test_java_library_module_javacopts(name): + analysis_test( + name = name, + impl = _test_java_library_module_javacopts_impl, + target = "//test/java/common/rules:module_javacopts_helper", + ) + +def _test_java_library_module_javacopts_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.javacopts().contains_at_least([ + "--add-exports=export/one=ALL-UNNAMED", + "--add-exports=export/two=ALL-UNNAMED", + ]) + + java_info = java_info_subject.from_target(env, target) + java_info.module_flags().add_exports().contains_exactly([ + "export/one", + "export/two", + ]) + java_info.module_flags().add_opens().contains_exactly([ + "open/one", + "open/two", + ]) + +def _test_java_library_forwarded_deps(name): + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + util.helper_target( + java_library, + name = name + "/b1", + exports = [name + "/a"], + ) + util.helper_target( + java_library, + name = name + "/b2", + exports = [name + "/a"], + ) + util.helper_target( + java_library, + name = name + "/c1", + srcs = ["c1.java"], + deps = [name + "/b1"], + ) + util.helper_target( + java_library, + name = name + "/c2", + srcs = ["c2.java"], + deps = [name + "/b2"], + ) + + analysis_test( + name = name, + impl = _test_java_library_forwarded_deps_impl, + targets = { + "a": name + "/a", + "c1": name + "/c1", + "c2": name + "/c2", + }, + ) + +def _test_java_library_forwarded_deps_impl(env, targets): + a_info = java_info_subject.from_target(env, targets.a) + c1_info = java_info_subject.from_target(env, targets.c1) + c2_info = java_info_subject.from_target(env, targets.c2) + + a_jars = a_info.compilation_args().actual.compile_jars.to_list() + c1_info.compilation_info().compilation_classpath().contains_at_least(a_jars) + c2_info.compilation_info().compilation_classpath().contains_at_least(a_jars) + +# Regression test for b/5773894 +def _test_java_library_transitive_strict_deps(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/c", + srcs = ["C.java"], + ) + util.helper_target( + java_library, + name = name + "/b", + srcs = ["B.java"], + deps = [name + "/c"], + ) + util.helper_target( + java_library, + name = name + "/a", + exports = [name + "/b"], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:experimental_strict_java_deps": "ERROR", + }, + impl = _test_java_library_transitive_strict_deps_impl, + target = name + "/a", + ) + +def _test_java_library_transitive_strict_deps_impl(env, target): + a_info = java_info_subject.from_target(env, target) + a_info.compilation_args().compile_jars().contains_exactly([ + "{package}/lib{test_name}/b-hjar.jar", + ]) + +def _test_java_library_emit_output_deps(name): + util.helper_target( + java_library, + name = name + "/b", + srcs = ["B.java"], + ) + util.helper_target( + java_library, + name = name + "/a", + exports = [name + "/b"], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:java_deps": True, + }, + impl = _test_java_library_emit_output_deps_impl, + targets = { + "a": name + "/a", + "b": name + "/b", + }, + ) + +def _test_java_library_emit_output_deps_impl(env, targets): + javac_action_subject.of(env, targets.b, "{package}/lib{name}.jar").outputs().contains( + "{package}/lib{name}.jdeps", + ) + + javac_action_subject.of(env, targets.a, "{package}/lib{name}.jar").outputs().contains_exactly([ + "{package}/lib{name}.jar", + "{package}/lib{name}-native-header.jar", + "{package}/lib{name}.jar_manifest_proto", + ]) + +def _test_java_library_deps_without_srcs(name): + util.helper_target( + java_library, + name = name + "/b", + srcs = ["B.java"], + ) + util.helper_target( + java_library, + name = name + "/a", + deps = [name + "/b"], + ) + + analysis_test( + name = name, + expect_failure = True, + impl = _test_java_library_deps_without_srcs_impl, + target = name + "/a", + ) + +def _test_java_library_deps_without_srcs_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("deps not allowed without srcs"), + ) + +def _test_dependency_artifacts_with_exports(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/e", + srcs = ["E.java"], + ) + util.helper_target( + java_library, + name = name + "/d", + srcs = ["D.java"], + ) + util.helper_target( + java_library, + name = name + "/c", + srcs = ["C.java"], + exports = [name + "/e"], + ) + util.helper_target( + java_library, + name = name + "/b", + exports = [name + "/d"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["A.java"], + deps = [ + name + "/b", + name + "/c", + name + "/d", + ], + ) + + analysis_test( + name = name, + config_settings = { + "//command_line_option:experimental_java_classpath": "javabuilder", + }, + impl = _test_dependency_artifacts_with_exports_impl, + target = name + "/a", + ) + +def _test_dependency_artifacts_with_exports_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.deps_artifacts().contains_exactly([ + "{bin_path}/{package}/lib{test_name}/c-hjar.jdeps", + "{bin_path}/{package}/lib{test_name}/d-hjar.jdeps", + "{bin_path}/{package}/lib{test_name}/e-hjar.jdeps", + ]) + +def _test_exports_are_indirect_not_direct(name): + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + util.helper_target( + java_library, + name = name + "/b", + srcs = ["b.java"], + exports = [name + "/a"], + ) + util.helper_target( + java_library, + name = name + "/c", + srcs = ["c.java"], + deps = [name + "/b"], + ) + + analysis_test( + name = name, + impl = _test_exports_are_indirect_not_direct_impl, + targets = { + "b": name + "/b", + "c": name + "/c", + }, + ) + +def _test_exports_are_indirect_not_direct_impl(env, targets): + b_info = java_info_subject.from_target(env, targets.b) + c_info = java_info_subject.from_target(env, targets.c) + + b_info.compilation_info().compilation_classpath().contains_exactly([]) + + c_info.compilation_info().compilation_classpath().contains_at_least_predicates([ + matching.file_basename_equals("a-hjar.jar"), + matching.file_basename_equals("b-hjar.jar"), + ]) + +def _test_exports_runfiles(name): + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + data = ["data.txt"], + ) + util.helper_target( + java_library, + name = name + "/b", + srcs = ["b.java"], + exports = [name + "/a"], + ) + + analysis_test( + name = name, + impl = _test_exports_runfiles_impl, + target = name + "/b", + ) + +def _test_exports_runfiles_impl(env, target): + env.expect.that_target(target).runfiles().contains_exactly([ + "{workspace}/{package}/data.txt", + "{workspace}/{package}/lib{test_name}/a.jar", + "{workspace}/{package}/lib{test_name}/b.jar", + ]) + +def _test_exports_collect_source_jars(name): + util.helper_target( + java_library, + name = name + "/exp", + srcs = ["C.java"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["B.java"], + exports = [name + "/exp"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["A.java"], + deps = [name + "/lib"], + ) + + analysis_test( + name = name, + impl = _test_exports_collect_source_jars_impl, + target = name + "/a", + ) + +def _test_exports_collect_source_jars_impl(env, target): + java_info_subject.from_target(env, target).transitive_source_jars().contains_exactly([ + "{package}/lib{test_name}/a-src.jar", + "{package}/lib{test_name}/lib-src.jar", + "{package}/lib{test_name}/exp-src.jar", + ]) + +def _test_exported_plugins_are_inherited(name): + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + processor_class = "com.example.process.stuff", + ) + util.helper_target( + java_library, + name = name + "/exporting_lib", + srcs = ["ExportingLib.java"], + exported_plugins = [name + "/plugin"], + ) + util.helper_target( + java_library, + name = name + "/consuming_lib", + srcs = ["ConsumingLib.java"], + deps = [name + "/exporting_lib"], + ) + util.helper_target( + java_library, + name = name + "/leaf_lib", + srcs = ["LeafLib.java"], + deps = [name + "/consuming_lib"], + ) + + analysis_test( + name = name, + impl = _test_exported_plugins_are_inherited_impl, + targets = { + "consuming": name + "/consuming_lib", + "leaf": name + "/leaf_lib", + }, + ) + +def _test_exported_plugins_are_inherited_impl(env, targets): + # libconsuming_lib should include the plugin, since it directly depends on exporting_lib + javac_action_subject.of( + env, + targets.consuming, + "{package}/lib{test_name}/consuming_lib.jar", + ).processors().contains_exactly(["com.example.process.stuff"]) + + # but libleaf_lib should not, because its dependency is transitive. + javac_action_subject.of( + env, + targets.leaf, + "{package}/lib{test_name}/leaf_lib.jar", + ).processors().contains_exactly([]) + +def _test_exported_plugins_are_propagated_through_exports(name): + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + processor_class = "com.example.process.stuff", + ) + util.helper_target( + java_library, + name = name + "/exporting_plugins_lib", + srcs = ["ExportingLib.java"], + exported_plugins = [name + "/plugin"], + ) + util.helper_target( + java_library, + name = name + "/exporting_lib", + srcs = ["ExportingLib.java"], + exports = [name + "/exporting_plugins_lib"], + ) + util.helper_target( + java_library, + name = name + "/consuming_lib", + srcs = ["ConsumingLib.java"], + exports = [name + "/exporting_lib"], + deps = [name + "/exporting_lib"], + ) + util.helper_target( + java_library, + name = name + "/leaf_lib", + srcs = ["LeafLib.java"], + deps = [name + "/consuming_lib"], + ) + + analysis_test( + name = name, + impl = _test_exported_plugins_are_propagated_through_exports_impl, + targets = { + "exporting": name + "/exporting_lib", + "consuming": name + "/consuming_lib", + "leaf": name + "/leaf_lib", + }, + ) + +def _test_exported_plugins_are_propagated_through_exports_impl(env, targets): + # libexporting_lib should not include the plugin, only export it further. + javac_action_subject.of( + env, + targets.exporting, + "{package}/lib{test_name}/exporting_lib.jar", + ).processors().contains_exactly([]) + + # libconsuming_lib should pick up the plugin through the export on exporting_lib. + javac_action_subject.of( + env, + targets.consuming, + "{package}/lib{test_name}/consuming_lib.jar", + ).processors().contains_exactly(["com.example.process.stuff"]) + + # libleaf_lib should pick up the plugin through the (transitive) export on exporting_lib. + javac_action_subject.of( + env, + targets.leaf, + "{package}/lib{test_name}/leaf_lib.jar", + ).processors().contains_exactly(["com.example.process.stuff"]) + +def java_library_launcher_tests(name): + test_suite( + name = name, + tests = [ + _test_java_library_rule_outputs, + _test_java_library_action_graph, + _test_java_library_deps_of_genrule_are_not_on_classpath, + _test_java_library_compile_and_run_time_paths, + _test_java_library_files_to_compile, + _test_java_library_runtime_deps_are_not_on_classpath, + _test_java_library_runtime_deps_are_not_on_classpath_with_header_compilation, + _test_java_library_propagates_native_libraries, + _test_java_library_gen_source_no_processor_names, + _test_java_library_annotation_processing_using_javacopt, + _test_java_library_javacopts_with_location_expansion, + _test_java_library_invalid_plugin, + _test_java_library_plugin_with_runtime_deps, + _test_java_library_source_jar_without_annotation_processing, + _test_java_library_source_jars_with_source_jars, + _test_java_library_should_set_bootclasspath, + _test_java_library_command_line_contains_target_label_and_rule_kind, + _test_java_library_compilation_info_provider, + _test_java_library_native_header_outputs, + _test_java_library_module_javacopts, + _test_java_library_forwarded_deps, + _test_java_library_transitive_strict_deps, + _test_java_library_emit_output_deps, + _test_java_library_deps_without_srcs, + _test_dependency_artifacts_with_exports, + _test_exports_are_indirect_not_direct, + _test_exports_runfiles, + _test_exports_collect_source_jars, + _test_exported_plugins_are_inherited, + _test_exported_plugins_are_propagated_through_exports, + ], + ) diff --git a/test/java/common/rules/deploy_archive_builder_tests.bzl b/test/java/common/rules/deploy_archive_builder_tests.bzl new file mode 100644 index 00000000..727790f8 --- /dev/null +++ b/test/java/common/rules/deploy_archive_builder_tests.bzl @@ -0,0 +1,47 @@ +"""Tests for DeployArchiveBuilder.""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_binary.bzl", "java_binary") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_toolchain") + +def _test_custom_singlejar(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + ) + util.helper_target( + java_binary, + name = name + "/binary", + srcs = [name + "/main.java"], + main_class = "com.google.test.main", + ) + + analysis_test( + name = name, + impl = _test_custom_singlejar_impl, + target = name + "/binary", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + # Starlark rules are only used with Bazel 8 onwards. + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_custom_singlejar_impl(env, target): + action = env.expect.that_target(target).action_named("JavaDeployJar") + action.inputs().contains_at_least_predicates( + [ + matching.file_path_matches("*/test_custom_singlejar/binary.jar"), + ], + ) + +def deploy_archive_builder_test_suite(name): + """Test suite for java_binary deploy archive.""" + test_suite( + name = name, + tests = [ + _test_custom_singlejar, + ], + ) diff --git a/test/java/common/rules/java_binary_tests.bzl b/test/java/common/rules/java_binary_tests.bzl index 08386ad1..b483516d 100644 --- a/test/java/common/rules/java_binary_tests.bzl +++ b/test/java/common/rules/java_binary_tests.bzl @@ -1,5 +1,7 @@ """Tests for the java_binary rule""" +load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") @@ -7,7 +9,11 @@ load("@rules_testing//lib:truth.bzl", "matching", "subjects") load("@rules_testing//lib:util.bzl", "util") load("//java:java_binary.bzl", "java_binary") load("//java:java_library.bzl", "java_library") +load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") +load("//test/java/testutil:helper.bzl", "always_passes") load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_toolchain") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") load("//test/java/testutil:rules/forward_java_info.bzl", "java_info_forwarding_rule") @@ -18,7 +24,6 @@ def _test_java_binary_provides_binary_java_info(name): name = name, impl = _test_java_binary_provides_binary_java_info_impl, target = Label(":bin"), - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_java_binary_provides_binary_java_info_impl(env, target): @@ -150,9 +155,6 @@ def _test_java_binary_propagates_direct_native_libraries(name): name = name, impl = _test_java_binary_propagates_direct_native_libraries_impl, target = name + "/binary", - # in Bazel 6, the windows stub was created by a bespoke, native and - # opaque-to-Starlark LauncherFileWriteAction - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_java_binary_propagates_direct_native_libraries_impl(env, target): @@ -171,6 +173,238 @@ def _test_java_binary_propagates_direct_native_libraries_impl(env, target): matching.str_matches("-Djava.library.path=${JAVA_RUNFILES}/*/test_java_binary_propagates_direct_native_libraries"), ) +def _test_java_compile_only(name): + util.helper_target( + java_library, + name = name + "/hello_library", + srcs = ["HelloLibrary.java"], + ) + util.helper_target( + java_binary, + name = name + "/main", + srcs = ["Main.java"], + main_class = "main.Main", + deps = [name + "/hello_library"], + ) + + analysis_test( + name = name, + impl = _test_java_compile_only_impl, + target = name + "/main", + ) + +def _test_java_compile_only_impl(env, target): + # Assert that the compilation output is exactly main jar, and does not contain a variant of + # hello_library.jar. + env.expect.that_target(target).output_group( + "compilation_outputs", + ).contains_exactly(["{package}/{name}.jar"]) + +def _test_java_binary_can_set_transitive_validation(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + env_name = name + "_env" + util.helper_target( + java_library, + name = env_name + "_leaf", + srcs = ["A.java"], + neverlink = True, # add runtime_classpath to validation output group + ) + util.helper_target( + java_binary, + name = env_name, + srcs = ["Env.java"], + deps = [env_name + "_leaf"], + neverlink = True, # add runtime_classpath to validation output group + ) + util.helper_target( + java_binary, + name = name + "_bin", + srcs = ["Bin.java"], + data = [env_name], + deploy_env = [env_name], + create_executable = False, + ) + + analysis_test( + name = name, + impl = _test_java_binary_can_set_transitive_validation_impl, + targets = { + "bin": name + "_bin", + "env": env_name, + }, + # Turn off other validations + config_settings = { + "//command_line_option:experimental_run_android_lint_on_java_rules": False, + "//command_line_option:experimental_one_version_enforcement": "OFF", + }, + ) + +def _test_java_binary_can_set_transitive_validation_impl(env, targets): + # ensure the env target has validation outputs + env.expect.that_target(targets.env).output_group("_validation").contains_at_least([ + "{package}/{name}.jar", + "{package}/lib{name}_leaf.jar", + ]) + + # ensure they don't propagate to `bin` because they're a part of the `deploy_env` + env.expect.that_target(targets.bin).output_group("_validation").contains_exactly([]) + +def _test_one_version_check_action(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/c", + srcs = [name + "/c.java"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = [name + "/a.java"], + deps = [name + "/c"], + ) + util.helper_target( + java_binary, + name = name + "/b", + srcs = [name + "/b.java"], + deps = [name + "/a"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_action_impl, + target = name + "/b", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + attrs = { + "_windows_constraints": attr.label_list( + default = [paths.join(semantics.PLATFORMS_ROOT, "os:windows")], + ), + }, + ) + +def _test_one_version_check_action_impl(env, target): + assert_target = env.expect.that_target(target) + assert_target.default_outputs().contains_exactly([ + "{package}/{test_name}/b.jar", + "{package}/{test_name}/b" + (".exe" if helper.is_target_platform_windows(env.ctx) else ""), + ]) + assert_target.output_group("_validation").contains( + "{package}/{name}-one-version.txt", + ) + assert_action = assert_target.action_generating("{package}/{name}-one-version.txt") + assert_action.mnemonic().equals("JavaOneVersion") + assert_action.inputs().contains_at_least([ + "{package}/{test_name}/b.jar", + "{package}/lib{test_name}/a.jar", + "{package}/lib{test_name}/c.jar", + ]) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist", + "--inputs", + "{bindir}/{package}/{test_name}/b.jar,//{package}:{test_name}/b", + "{bindir}/{package}/lib{test_name}/a.jar,//{package}:{test_name}/a", + "{bindir}/{package}/lib{test_name}/c.jar,//{package}:{test_name}/c", + ]).in_order() + +def _test_one_version_check_violations_allowed(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_binary, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_violations_allowed_impl, + target = name + "/foo", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "WARNING", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_violations_allowed_impl(env, target): + assert_action = env.expect.that_target(target).action_generating( + "{package}/{name}-one-version.txt", + ) + env.expect.that_target(target).output_group("_validation").contains( + "{package}/{name}-one-version.txt", + ) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist", + "--succeed_on_found_violations", + "--inputs", + "{bindir}/{package}/{test_name}/foo.jar,//{package}:{test_name}/foo", + ]).in_order() + +def _test_one_version_check_disabled(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_binary, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_disabled_impl, + target = name + "/foo", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "OFF", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_disabled_impl(env, target): + action_mnemonics = [a.mnemonic for a in env.expect.that_target(target).actual.actions] + env.expect.that_collection(action_mnemonics).not_contains("JavaOneVersion") + def java_binary_tests(name): test_suite( name = name, @@ -179,5 +413,10 @@ def java_binary_tests(name): _test_stamp_conversion_does_not_override_int, _test_java_binary_attributes, _test_java_binary_propagates_direct_native_libraries, + _test_java_compile_only, + _test_java_binary_can_set_transitive_validation, + _test_one_version_check_action, + _test_one_version_check_violations_allowed, + _test_one_version_check_disabled, ], ) diff --git a/test/java/common/rules/java_import_tests.bzl b/test/java/common/rules/java_import_tests.bzl index e949e173..35b713df 100644 --- a/test/java/common/rules/java_import_tests.bzl +++ b/test/java/common/rules/java_import_tests.bzl @@ -293,6 +293,33 @@ def _test_src_jars_impl(env, target): "{package}/library.srcjar", ]) +def _test_srcjar_added_to_validation_output_group(name): + util.helper_target( + java_import, + name = name + "/libraryjar_with_srcjar", + jars = ["import.jar"], + srcjar = "library.srcjar", + ) + + analysis_test( + name = name, + impl = _test_srcjar_added_to_validation_output_group_impl, + target = name + "/libraryjar_with_srcjar", + # Starlark rules are only used with Bazel 8 onwards. + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_srcjar_added_to_validation_output_group_impl(env, target): + assert_java_info = java_info_subject.from_target(env, target) + assert_java_info.outputs().source_output_jars().contains_exactly([ + "{package}/library.srcjar", + ]) + + # Check that the srcjar is in the _validation output group. + env.expect.that_target(target).output_group("_validation").contains_at_least([ + "{package}/library.srcjar", + ]) + def _test_from_genrule(name): target_name = name + "/library-jar" util.helper_target( @@ -631,11 +658,16 @@ def _test_duplicate_jars_through_filegroup_impl(env, target): def _test_runtime_deps_are_not_on_classpath(name): target_name = name + "/depends_on_runtimedep" + util.helper_target( + java_import, + name = target_name + "/import_runtime", + jars = ["import_runtime.jar"], + ) util.helper_target( java_import, name = target_name + "/import_dep", jars = ["import_compile.jar"], - runtime_deps = ["import_runtime.jar"], + runtime_deps = [target_name + "/import_runtime"], ) util.helper_target( java_library, @@ -748,8 +780,6 @@ def _test_neverlink_is_populated(name): name = name, impl = _test_neverlink_is_populated_impl, target = target_name, - # in Bazel 6, JavaInfo._neverlink isn't exposed to Starlark - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_neverlink_is_populated_impl(env, target): @@ -933,6 +963,7 @@ def java_import_tests(name): _test_java_library_allows_import_in_deps, _test_module_flags, _test_src_jars, + _test_srcjar_added_to_validation_output_group, _test_from_genrule, _test_transitive_dependencies, _test_exposes_java_provider, diff --git a/test/java/common/rules/java_launcher_tests.bzl b/test/java/common/rules/java_launcher_tests.bzl new file mode 100644 index 00000000..6faaa93f --- /dev/null +++ b/test/java/common/rules/java_launcher_tests.bzl @@ -0,0 +1,71 @@ +"""Tests for the "launcher" attribute and "--java_launcher" flag.""" + +load("@rules_cc//cc:cc_binary.bzl", "cc_binary") +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_binary.bzl", "java_binary") + +def _test_overridden_incompatible_launcher(name): + # Check analysis succeeds even though --java_launcher refers to an incompatible target + # when the "use_launcher" attribute is set to False. + util.helper_target( + rule = cc_binary, + name = name + "/launcher", + srcs = select({ + "@platforms//cpu:ppc": [name + "/launcher.cc"], + }), + ) + + util.helper_target( + rule = java_binary, + name = name + "/bin", + srcs = [name + "/Bin.java"], + use_launcher = False, + ) + + analysis_test( + name = name, + impl = lambda env, target: True, + target = name + "/bin", + config_settings = { + "//command_line_option:java_launcher": Label(name + "/launcher"), + "//command_line_option:cpu": "k8", + }, + ) + +def _test_launcher_with_create_executable_false_fails(name): + util.helper_target( + rule = cc_binary, + name = name + "/launcher", + srcs = [name + "/launcher.cc"], + ) + + util.helper_target( + rule = java_binary, + name = name + "/bin", + srcs = [name + "/Bin.java"], + launcher = name + "/launcher", + create_executable = False, + ) + + analysis_test( + name = name, + impl = _test_launcher_with_create_executable_false_fails_impl, + target = name + "/bin", + expect_failure = True, + ) + +def _test_launcher_with_create_executable_false_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("launcher specified but create_executable is false"), + ) + +def java_launcher_tests(name): + test_suite( + name = name, + tests = [ + _test_overridden_incompatible_launcher, + _test_launcher_with_create_executable_false_fails, + ], + ) diff --git a/test/java/common/rules/java_library_tests.bzl b/test/java/common/rules/java_library_tests.bzl index 58a282f9..4115b121 100644 --- a/test/java/common/rules/java_library_tests.bzl +++ b/test/java/common/rules/java_library_tests.bzl @@ -1,5 +1,6 @@ """Tests for the java_library rule""" +load("@bazel_features//:features.bzl", "bazel_features") load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") @@ -8,7 +9,9 @@ load("@rules_testing//lib:util.bzl", "util") load("//java:java_library.bzl", "java_library") load("//java:java_plugin.bzl", "java_plugin") load("//java/common:java_info.bzl", "JavaInfo") +load("//test/java/testutil:helper.bzl", "always_passes") load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") +load("//test/java/testutil:javac_action_subject.bzl", "javac_action_subject") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") load("//test/java/testutil:rules/forward_java_info.bzl", "java_info_forwarding_rule") load("//test/java/testutil:rules/wrap_java_info.bzl", "JavaInfoWrappingInfo", "java_info_wrapping_rule") @@ -267,8 +270,6 @@ def _test_propagates_direct_native_libraries(name): name = name, impl = _test_propagates_direct_native_libraries_impl, target = target_name, - # LibraryToLink.library_indentifier only available from Bazel 8 - attr_values = {"tags": ["min_bazel_8"]}, ) def _test_propagates_direct_native_libraries_impl(env, target): @@ -311,6 +312,42 @@ def _test_exposes_native_library_info_impl(env, target): assert_lib.dynamic_library().basename().contains("mynativedep") +def _test_strict_java_deps(name, strict_java_deps): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/jl", + srcs = ["A.java"], + ) + + analysis_test( + name = name, + impl = _test_strict_java_deps_impl, + target = name + "/jl", + config_settings = {"//command_line_option:experimental_strict_java_deps": strict_java_deps}, + attrs = {"expected_strict_java_deps": attr.string()}, + attr_values = {"expected_strict_java_deps": strict_java_deps}, + ) + +def _test_strict_java_deps_impl(env, target): + # Note that if --experimental_strict_java_deps=OFF, we may not set --strict_java_deps in the + # javac action's argv at all; the "OFF" value (which is equivalent to an unset flag) in that + # case is injected by javac_action_subject for convenience and canonicalization. + expect_that_javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + expect_that_javac_action.strict_java_deps().contains_exactly([env.ctx.attr.expected_strict_java_deps]) + +def _test_strict_java_deps_off(name): + _test_strict_java_deps(name, "OFF") + +def _test_strict_java_deps_warn(name): + _test_strict_java_deps(name, "WARN") + +def _test_strict_java_deps_error(name): + _test_strict_java_deps(name, "ERROR") + def java_library_tests(name): test_suite( name = name, @@ -321,5 +358,8 @@ def java_library_tests(name): _test_java_library_attributes, _test_propagates_direct_native_libraries, _test_exposes_native_library_info, + _test_strict_java_deps_off, + _test_strict_java_deps_warn, + _test_strict_java_deps_error, ], ) diff --git a/test/java/common/rules/java_plugin_tests.bzl b/test/java/common/rules/java_plugin_tests.bzl index 646de647..71c2d156 100644 --- a/test/java/common/rules/java_plugin_tests.bzl +++ b/test/java/common/rules/java_plugin_tests.bzl @@ -1,10 +1,12 @@ """Tests for the java_plugin rule""" load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "subjects") load("@rules_testing//lib:util.bzl", "util") load("//java:java_library.bzl", "java_library") load("//java:java_plugin.bzl", "java_plugin") load("//java/common:java_plugin_info.bzl", "JavaPluginInfo") +load("//java/common:proguard_spec_info.bzl", "ProguardSpecInfo") load("//test/java/testutil:java_info_subject.bzl", "java_plugin_info_subject") def _test_exposes_plugins_to_starlark(name): @@ -75,11 +77,313 @@ def _test_exposes_api_generating_plugins_to_starlark_impl(env, target): assert_api_plugin_data.processor_data().contains_exactly(["{package}/pluginfile.dat"]) assert_api_plugin_data.equals(target[JavaPluginInfo].plugins) +def _test_not_empty_processor_class(name): + util.helper_target( + java_library, + name = name + "/deps", + srcs = ["Deps.java"], + ) + util.helper_target( + java_plugin, + name = name + "/processor", + srcs = ["Processor.java"], + processor_class = "com.google.test.Processor", + deps = [name + "/deps"], + ) + + analysis_test( + name = name, + impl = _test_not_empty_processor_class_impl, + target = name + "/processor", + ) + +def _test_not_empty_processor_class_impl(env, target): + plugin_info = java_plugin_info_subject.from_target(env, target) + plugin_info.plugins().processor_classes().contains_exactly(["com.google.test.Processor"]) + + plugin_info.plugins().processor_jars().contains_exactly([ + "{package}/lib{name}.jar", + "{package}/lib{test_name}/deps.jar", + ]) + +def _test_empty_processor_class(name): + util.helper_target( + java_library, + name = name + "/deps", + srcs = ["Deps.java"], + ) + util.helper_target( + java_plugin, + name = name + "/bugchecker", + srcs = ["BugChecker.java"], + deps = [":" + name + "/deps"], + ) + + analysis_test( + name = name, + impl = _test_empty_processor_class_impl, + target = name + "/bugchecker", + ) + +def _test_empty_processor_class_impl(env, target): + plugin_info = java_plugin_info_subject.from_target(env, target) + plugin_info.plugins().processor_classes().contains_exactly([]) + plugin_info.plugins().processor_jars().contains_exactly([ + "{package}/lib{name}.jar", + "{package}/lib{test_name}/deps.jar", + ]) + +def _test_empty_processor_class_target(name): + util.helper_target( + java_library, + name = name + "/deps", + srcs = ["Deps.java"], + ) + util.helper_target( + java_plugin, + name = name + "/bugchecker", + srcs = ["BugChecker.java"], + deps = [":" + name + "/deps"], + ) + util.helper_target( + java_library, + name = name + "/empty", + plugins = [":" + name + "/bugchecker"], + ) + + analysis_test( + name = name, + impl = _test_empty_processor_class_target_impl, + target = name + "/empty", + ) + +def _test_empty_processor_class_target_impl(env, target): + env.expect.that_target(target).action_generating("{package}/lib{name}.jar").inputs().contains_at_least([ + "{package}/lib{test_name}/bugchecker.jar", + "{package}/lib{test_name}/deps.jar", + ]) + +def _new_proguard_info_subject(info, meta): + return struct( + specs = lambda: subjects.depset_file(info.specs, meta.derive("specs")), + ) + +def _test_java_plugin_exports_transitive_proguard_specs(name): + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + proguard_specs = ["plugin.pro"], + ) + util.helper_target( + java_library, + name = name + "/dep", + srcs = ["Dep.java"], + proguard_specs = ["dep.pro"], + ) + util.helper_target( + java_plugin, + name = name + "/top", + srcs = ["Top.java"], + plugins = [":" + name + "/plugin"], + proguard_specs = ["top.pro"], + deps = [":" + name + "/dep"], + ) + + analysis_test( + name = name, + impl = _test_java_plugin_exports_transitive_proguard_specs_impl, + target = name + "/top", + # Before Bazel 8, native rules use the native ProguardSpecProvider + attr_values = {"tags": ["min_bazel_8"]}, + provider_subject_factories = [struct( + type = ProguardSpecInfo, + name = "ProguardInfo", + factory = _new_proguard_info_subject, + )], + ) + +def _test_java_plugin_exports_transitive_proguard_specs_impl(env, target): + env.expect.that_target(target).provider(ProguardSpecInfo).specs().contains_exactly( + [ + "{package}/validated_proguard/{test_name}/top/{package}/top.pro_valid", + "{package}/validated_proguard/{test_name}/dep/{package}/dep.pro_valid", + ], + ) + +def _test_java_plugin_validates_proguard_specs(name): + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + proguard_specs = ["plugin.pro"], + ) + + analysis_test( + name = name, + impl = _test_java_plugin_validates_proguard_specs_impl, + target = name + "/plugin", + ) + +def _test_java_plugin_validates_proguard_specs_impl(env, target): + output_file = None + for f in target.output_groups["_hidden_top_level_INTERNAL_"].to_list(): + if f.basename == "plugin.pro_valid": + output_file = f + break + env.expect.that_target(target).action_generating( + output_file.short_path, + ).inputs().contains_at_least( + ["{package}/plugin.pro"], + ) + +def _test_java_plugin_validates_transitive_proguard_specs(name): + util.helper_target( + java_library, + name = name + "/transitive", + srcs = ["Transitive.java"], + proguard_specs = ["transitive.pro"], + ) + util.helper_target( + java_plugin, + name = name + "/plugin", + srcs = ["Plugin.java"], + deps = [":" + name + "/transitive"], + ) + + analysis_test( + name = name, + impl = _test_java_plugin_validates_transitive_proguard_specs_impl, + targets = { + "transitive": name + "/transitive", + "plugin": name + "/plugin", + }, + ) + +def _test_java_plugin_validates_transitive_proguard_specs_impl(env, targets): + output_file = None + for f in targets.plugin.output_groups["_hidden_top_level_INTERNAL_"].to_list(): + if f.basename == "transitive.pro_valid": + output_file = f + break + + env.expect.that_target(targets.transitive).action_generating( + output_file.short_path, + ).inputs().contains_at_least(["{package}/transitive.pro"]) + +def _test_generates_api(name): + util.helper_target( + java_plugin, + name = name + "/api_generating", + srcs = ["ApiGeneratingPlugin.java"], + generates_api = True, + processor_class = "ApiGeneratingPlugin", + ) + + analysis_test( + name = name, + impl = _test_generates_api_impl, + target = name + "/api_generating", + ) + +def _test_generates_api_impl(env, target): + plugin_info = java_plugin_info_subject.from_target(env, target) + plugin_info.plugins().processor_classes().contains_exactly(["ApiGeneratingPlugin"]) + plugin_info.api_generating_plugins().processor_classes().contains_exactly(["ApiGeneratingPlugin"]) + plugin_info.plugins().processor_jars().contains_exactly([ + "{package}/lib{name}.jar", + ]) + plugin_info.api_generating_plugins().processor_jars().contains_exactly([ + "{package}/lib{name}.jar", + ]) + +def _test_generates_implementation(name): + util.helper_target( + java_plugin, + name = name + "/impl_generating", + srcs = ["ImplGeneratingPlugin.java"], + generates_api = False, + processor_class = "ImplGeneratingPlugin", + ) + + analysis_test( + name = name, + impl = _test_generates_implementation_impl, + target = name + "/impl_generating", + ) + +def _test_generates_implementation_impl(env, target): + plugin_info = java_plugin_info_subject.from_target(env, target) + plugin_info.plugins().processor_classes().contains_exactly(["ImplGeneratingPlugin"]) + plugin_info.api_generating_plugins().processor_classes().contains_exactly([]) + plugin_info.plugins().processor_jars().contains_exactly([ + "{package}/lib{test_name}/impl_generating.jar", + ]) + plugin_info.api_generating_plugins().processor_jars().contains_exactly([]) + +def _test_plugin_data_in_provider(name): + util.helper_target( + java_plugin, + name = name + "/impl_generating", + srcs = ["ImplGeneratingPlugin.java"], + data = ["data.txt"], + generates_api = False, + processor_class = "ImplGeneratingPlugin", + ) + + analysis_test( + name = name, + impl = _test_plugin_data_in_provider_impl, + target = name + "/impl_generating", + ) + +def _test_plugin_data_in_provider_impl(env, target): + plugin_info = java_plugin_info_subject.from_target(env, target) + plugin_info.plugins().processor_data().contains_exactly([ + "{package}/data.txt", + ]) + +def _test_plugin_data_in_action_inputs(name): + util.helper_target( + java_plugin, + name = name + "/impl_generating_lib", + srcs = ["ImplGeneratingPlugin.java"], + data = ["data.txt"], + generates_api = False, + processor_class = "ImplGeneratingPlugin", + ) + util.helper_target( + java_library, + name = name + "/lib", + plugins = [":" + name + "/impl_generating_lib"], + ) + + analysis_test( + name = name, + impl = _test_plugin_data_in_action_inputs_impl, + target = name + "/lib", + ) + +def _test_plugin_data_in_action_inputs_impl(env, target): + env.expect.that_target(target).action_generating("{package}/lib{name}.jar").inputs().contains_at_least([ + "{package}/data.txt", + ]) + def java_plugin_tests(name): test_suite( name = name, tests = [ _test_exposes_plugins_to_starlark, _test_exposes_api_generating_plugins_to_starlark, + _test_not_empty_processor_class, + _test_empty_processor_class, + _test_empty_processor_class_target, + _test_generates_api, + _test_plugin_data_in_provider, + _test_plugin_data_in_action_inputs, + _test_java_plugin_exports_transitive_proguard_specs, + _test_java_plugin_validates_proguard_specs, + _test_java_plugin_validates_transitive_proguard_specs, + _test_generates_implementation, ], ) diff --git a/test/java/common/rules/java_single_jar_tests.bzl b/test/java/common/rules/java_single_jar_tests.bzl new file mode 100644 index 00000000..488aab3f --- /dev/null +++ b/test/java/common/rules/java_single_jar_tests.bzl @@ -0,0 +1,169 @@ +"""Tests for the java_single_jar rule""" + +load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching") +load("@rules_testing//lib:util.bzl", "util") +load("//java:java_single_jar.bzl", "java_single_jar") +load("//java/common:java_semantics.bzl", "semantics") + +def _test_java_single_jar_basic(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + deps = ["1.jar", "2.jar"], + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_basic_impl, + target = name + "/jar", + ) + +def _test_java_single_jar_basic_impl(env, target): + assert_that_action = env.expect.that_target(target).action_named("JavaSingleJar") + assert_that_action.argv().contains_at_least([ + "--sources", + "{package}/1.jar", + "{package}/2.jar", + "--output", + "{bindir}/{package}/{name}.jar", + "--normalize", + "--dont_change_compression", + "--exclude_build_data", + "--multi_release", + ]).in_order() + +def _test_java_single_jar_force_enable_stamping(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + stamp = 1, + exclude_build_data = False, + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_force_enable_stamping_impl, + targets = { + "jar": name + "/jar", + "build_info": semantics.BUILD_INFO_TRANSLATOR_LABEL, + }, + ) + +def _test_java_single_jar_force_enable_stamping_impl(env, targets): + assert_that_action = env.expect.that_target(targets.jar).action_named("JavaSingleJar") + assert_that_action.contains_flag_values([ + ("--build_info_file", f.path) + for f in targets.build_info[OutputGroupInfo].non_redacted_build_info_files.to_list() + ]) + +def _test_java_single_jar_force_disable_stamping(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + stamp = 0, + exclude_build_data = False, + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_force_disable_stamping_impl, + targets = { + "jar": name + "/jar", + "build_info": semantics.BUILD_INFO_TRANSLATOR_LABEL, + }, + ) + +def _test_java_single_jar_force_disable_stamping_impl(env, targets): + assert_that_action = env.expect.that_target(targets.jar).action_named("JavaSingleJar") + assert_that_action.contains_flag_values([ + ("--build_info_file", f.path) + for f in targets.build_info[OutputGroupInfo].redacted_build_info_files.to_list() + ]) + +def _test_java_single_jar_stamping_enabled_build_data_excluded_fails(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + stamp = 1, + exclude_build_data = True, + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_stamping_enabled_build_data_excluded_fails_impl, + target = name + "/jar", + expect_failure = True, + ) + +def _test_java_single_jar_stamping_enabled_build_data_excluded_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("Enabling stamping has not effect with exclude_build_data enabled"), + ) + +def _test_java_single_jar_stamp_attr_auto_stamp_flag_enabled(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + stamp = -1, + exclude_build_data = False, + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_stamp_attr_auto_stamp_flag_enabled_impl, + targets = { + "jar": name + "/jar", + "build_info": semantics.BUILD_INFO_TRANSLATOR_LABEL, + }, + config_settings = { + "//command_line_option:stamp": True, + }, + ) + +def _test_java_single_jar_stamp_attr_auto_stamp_flag_enabled_impl(env, targets): + assert_that_action = env.expect.that_target(targets.jar).action_named("JavaSingleJar") + assert_that_action.contains_flag_values([ + ("--build_info_file", f.path) + for f in targets.build_info[OutputGroupInfo].non_redacted_build_info_files.to_list() + ]) + +def _test_java_single_jar_stamp_attr_auto_stamp_flag_disabled(name): + util.helper_target( + java_single_jar, + name = name + "/jar", + stamp = -1, + exclude_build_data = False, + ) + + analysis_test( + name = name, + impl = _test_java_single_jar_stamp_attr_auto_stamp_flag_disabled_impl, + targets = { + "jar": name + "/jar", + "build_info": semantics.BUILD_INFO_TRANSLATOR_LABEL, + }, + config_settings = { + "//command_line_option:stamp": False, + }, + ) + +def _test_java_single_jar_stamp_attr_auto_stamp_flag_disabled_impl(env, targets): + assert_that_action = env.expect.that_target(targets.jar).action_named("JavaSingleJar") + assert_that_action.contains_flag_values([ + ("--build_info_file", f.path) + for f in targets.build_info[OutputGroupInfo].redacted_build_info_files.to_list() + ]) + +def java_single_jar_tests(name): + test_suite( + name = name, + tests = [ + _test_java_single_jar_basic, + _test_java_single_jar_force_enable_stamping, + _test_java_single_jar_force_disable_stamping, + _test_java_single_jar_stamping_enabled_build_data_excluded_fails, + _test_java_single_jar_stamp_attr_auto_stamp_flag_enabled, + _test_java_single_jar_stamp_attr_auto_stamp_flag_disabled, + ], + ) diff --git a/test/java/common/rules/java_test_tests.bzl b/test/java/common/rules/java_test_tests.bzl index 4cc39ca2..995872f1 100644 --- a/test/java/common/rules/java_test_tests.bzl +++ b/test/java/common/rules/java_test_tests.bzl @@ -1,14 +1,75 @@ """Tests for the java_test rule""" +load("@bazel_features//:features.bzl", "bazel_features") +load("@bazel_skylib//lib:paths.bzl", "paths") load("@rules_cc//cc:cc_binary.bzl", "cc_binary") load("@rules_cc//cc:cc_library.bzl", "cc_library") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") load("@rules_testing//lib:truth.bzl", "matching", "subjects") load("@rules_testing//lib:util.bzl", "util") +load("//java:java_binary.bzl", "java_binary") load("//java:java_library.bzl", "java_library") load("//java:java_test.bzl", "java_test") +load("//java/common:java_info.bzl", "JavaInfo") +load("//java/common:java_semantics.bzl", "semantics") +load("//java/common/rules:java_helper.bzl", "helper") +load("//test/java/testutil:helper.bzl", "always_passes") +load("//test/java/testutil:mock_cc_toolchain.bzl", "mock_cc_toolchain") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_runtime_toolchain", "mock_java_toolchain") +load("//test/java/testutil:mock_test_toolchain.bzl", "mock_test_toolchains") load("//test/java/testutil:rules/custom_java_info_rule.bzl", "custom_java_info_rule") +def _test_java_test_is_test_only(name): + util.helper_target( + java_test, + name = name + "/test", + srcs = [name + "/Test.java"], + ) + + util.helper_target( + java_library, + name = name + "/lib", + srcs = [name + "/Lib.java"], + deps = [name + "/test"], + ) + + analysis_test( + name = name, + impl = _test_java_test_is_test_only_impl, + target = name + "/lib", + expect_failure = True, + ) + +def _test_java_test_is_test_only_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("non-test target '*/lib' depends on testonly target '*/test'"), + ) + +def _test_deps_without_srcs_fails(name): + util.helper_target( + rule = java_library, + name = name + "/lib", + srcs = [name + "/Lib.java"], + ) + + util.helper_target( + rule = java_test, + name = name + "/test", + deps = [name + "/lib"], + ) + + analysis_test( + name = name, + target = name + "/test", + impl = _test_deps_without_srcs_fails_impl, + expect_failure = True, + ) + +def _test_deps_without_srcs_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("deps not allowed without srcs"), + ) + def _test_java_test_propagates_direct_native_libraries(name): util.helper_target( cc_library, @@ -56,9 +117,6 @@ def _test_java_test_propagates_direct_native_libraries(name): name = name, impl = _test_java_test_propagates_direct_native_libraries_impl, target = name + "/binary", - # in Bazel 6, the windows stub was created by a bespoke, native and - # opaque-to-Starlark LauncherFileWriteAction - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_java_test_propagates_direct_native_libraries_impl(env, target): @@ -77,10 +135,318 @@ def _test_java_test_propagates_direct_native_libraries_impl(env, target): matching.str_matches("-Djava.library.path=${JAVA_RUNFILES}/*/test_java_test_propagates_direct_native_libraries"), ) +def _test_coverage_uses_coverage_runner_for_main(name): + util.helper_target( + rule = java_test, + name = name + "/test", + srcs = [name + "/Test.java"], + ) + + analysis_test( + name = name, + impl = _test_coverage_uses_coverage_runner_for_main_impl, + target = name + "/test", + config_settings = { + "//command_line_option:collect_code_coverage": True, + }, + ) + +def _test_coverage_uses_coverage_runner_for_main_impl(env, target): + executable = target[DefaultInfo].files_to_run.executable.short_path + assert_action = env.expect.that_target(target).action_generating(executable) + if assert_action.actual.substitutions: + assert_java_start_class = assert_action.substitutions().get( + "%java_start_class%", + factory = lambda v, meta: subjects.str(v, meta.derive("java_start_class")), + ) + assert_java_start_class.contains("com.google.testing.coverage.JacocoCoverageRunner") + else: + # Windows + assert_java_start_class = assert_action.argv() + assert_java_start_class.contains("java_start_class=com.google.testing.coverage.JacocoCoverageRunner") + +def _test_stamp_values(name): + util.helper_target( + rule = java_test, + name = name + "/stamp_true", + srcs = [name + "/Test.java"], + stamp = True, + ) + + util.helper_target( + rule = java_test, + name = name + "/stamp_false", + srcs = [name + "/Test.java"], + stamp = False, + ) + + util.helper_target( + rule = java_test, + name = name + "/stamp_auto", + srcs = [name + "/Test.java"], + stamp = -1, + ) + + util.helper_target( + rule = java_test, + name = name + "/stamp_default", + srcs = [name + "/Test.java"], + ) + + analysis_test( + name = name, + targets = { + "stamp": name + "/stamp_true", + "nostamp": name + "/stamp_false", + "autostamp": name + "/stamp_auto", + "defaultstamp": name + "/stamp_default", + }, + impl = _test_stamp_values_impl, + ) + +def _test_stamp_values_impl(env, targets): + env.expect.that_target(targets.stamp).attr("stamp", factory = subjects.int).equals(1) + env.expect.that_target(targets.nostamp).attr("stamp", factory = subjects.int).equals(0) + env.expect.that_target(targets.defaultstamp).attr("stamp", factory = subjects.int).equals(0) + env.expect.that_target(targets.autostamp).attr("stamp", factory = subjects.int).equals(-1) + +def _test_add_test_support_to_compile_time_deps_flag(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + always_passes(name) + return + util.helper_target( + rule = java_test, + name = name + "/test", + srcs = [name + "/Test.java"], + ) + + analysis_test( + name = name, + targets = { + "add_support": name + "/test", + "no_add_support": name + "/test", + }, + attrs = { + "test_runner": attr.label(default = semantics.JAVA_TEST_RUNNER_LABEL), + "add_support": { + "@config_settings": { + "//command_line_option:experimental_add_test_support_to_compile_time_deps": True, + }, + }, + "no_add_support": { + "@config_settings": { + "//command_line_option:experimental_add_test_support_to_compile_time_deps": False, + }, + }, + }, + impl = _test_add_test_support_to_compile_time_deps_flag_impl, + ) + +def _test_add_test_support_to_compile_time_deps_flag_impl(env, targets): + compile_jars = env.ctx.attr.test_runner[JavaInfo].compile_jars + env.expect.that_target(targets.add_support).action_named("Javac").inputs().contains_at_least(compile_jars.to_list()) + env.expect.that_target(targets.no_add_support).action_named("Javac").inputs().contains_none_of(compile_jars.to_list()) + +def _test_mac_requires_darwin_for_execution(name): + util.helper_target( + rule = native.platform, + name = name + "/darwin_x86_64", + constraint_values = [ + "@platforms//os:macos", + "@platforms//cpu:x86_64", + ], + ) + + util.helper_target( + rule = java_test, + name = name + "/test", + srcs = [name + "/Test.java"], + use_launcher = False, + use_testrunner = 0, + ) + + util.helper_target( + rule = mock_cc_toolchain, + name = name + "/cc_toolchain", + cpu = "x86_64", + os = "macos", + ) + + toolchains = [Label(name + "/cc_toolchain")] + mock_test_toolchains( + name = name + "/test_toolchain", + cpu = "x86_64", + os = "macos", + ) + + analysis_test( + name = name, + target = name + "/test", + config_settings = { + "//command_line_option:platforms": [Label(name + "/darwin_x86_64")], + "//command_line_option:extra_toolchains": toolchains, + }, + impl = _test_mac_requires_darwin_for_execution_impl, + ) + +def _test_mac_requires_darwin_for_execution_impl(env, target): + env.expect.that_target(target).provider(testing.ExecutionInfo).requirements().contains_at_least( + {"requires-darwin": ""}, + ) + +def _test_java_test_sets_securiry_manager_property_jdk17(name): + util.helper_target( + java_test, + name = name + "/test", + srcs = ["FooTest.java"], + test_class = "FooTest", + ) + util.helper_target( + mock_java_runtime_toolchain, + name = name + "/toolchain", + version = 17, + ) + + analysis_test( + name = name, + impl = _test_java_test_sets_securiry_manager_property_jdk17_impl, + target = name + "/test", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_java_test_sets_securiry_manager_property_jdk17_impl(env, target): + executable = env.expect.that_target(target).executable().actual.short_path + assert_action = env.expect.that_target(target).action_generating(executable) + if assert_action.actual.substitutions: + # TemplateExpansion action on linux/mac + assert_action.substitutions().get("%jvm_flags%", factory = subjects.str).contains( + "-Djava.security.manager=allow", + ) + else: + # windows + assert_action.argv().contains_predicate( + matching.str_matches("-Djava.security.manager=allow"), + ) + +def _test_one_version_check_java_test(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_library, + name = name + "/foo", + srcs = [name + "/foo.java"], + ) + util.helper_target( + java_test, + name = name + "/foo_test", + srcs = [name + "/foo_test.java"], + deps = [name + "/foo"], + use_testrunner = False, + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + oneversion_allowlist = "one_version_allowlist", + oneversion_allowlist_for_tests = "one_version_allowlist_for_tests", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_java_test_impl, + target = name + "/foo_test", + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + attrs = { + "_windows_constraints": attr.label_list( + default = [paths.join(semantics.PLATFORMS_ROOT, "os:windows")], + ), + }, + ) + +def _test_one_version_check_java_test_impl(env, target): + assert_target = env.expect.that_target(target) + assert_target.default_outputs().contains_exactly([ + "{package}/{test_name}/foo_test.jar", + "{package}/{test_name}/foo_test" + (".exe" if helper.is_target_platform_windows(env.ctx) else ""), + ]) + assert_action = assert_target.action_generating( + "{package}/{name}-one-version.txt", + ) + tool = [f for f in assert_action.actual.inputs.to_list() if f.short_path.endswith("one_version_tool")][0] + assert_action.argv().contains_exactly([ + tool.path, + "--output", + "{bindir}/{package}/{name}-one-version.txt", + "--allowlist", + "{package}/one_version_allowlist_for_tests", + "--inputs", + "{bindir}/{package}/{test_name}/foo_test.jar,//{package}:{test_name}/foo_test", + "{bindir}/{package}/lib{test_name}/foo.jar,//{package}:{test_name}/foo", + ]).in_order() + +def _test_one_version_check_disabled_for_java_test(name): + if not bazel_features.rules.analysis_tests_can_transition_on_experimental_incompatible_flags: + # exit early because this test case would be a loading phase error otherwise + always_passes(name) + return + + util.helper_target( + java_test, + name = name + "/foo_test", + srcs = [name + "/foo.java"], + use_testrunner = False, + ) + util.helper_target( + java_binary, + name = name + "/foo_binary", + srcs = [name + "/foo.java"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + oneversion = "one_version_tool", + ) + + analysis_test( + name = name, + impl = _test_one_version_check_disabled_for_java_test_impl, + targets = { + "bin": name + "/foo_binary", + "test": name + "/foo_test", + }, + config_settings = { + "//command_line_option:experimental_one_version_enforcement": "ERROR", + "//command_line_option:one_version_enforcement_on_java_tests": False, + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_one_version_check_disabled_for_java_test_impl(env, targets): + binary_action_mnemonics = [a.mnemonic for a in env.expect.that_target(targets.bin).actual.actions] + test_action_mnemonics = [a.mnemonic for a in env.expect.that_target(targets.test).actual.actions] + env.expect.that_collection(binary_action_mnemonics).contains("JavaOneVersion") + env.expect.that_collection(test_action_mnemonics).not_contains("JavaOneVersion") + def java_test_tests(name): test_suite( name = name, tests = [ + _test_java_test_is_test_only, + _test_deps_without_srcs_fails, _test_java_test_propagates_direct_native_libraries, + _test_coverage_uses_coverage_runner_for_main, + _test_stamp_values, + _test_add_test_support_to_compile_time_deps_flag, + _test_mac_requires_darwin_for_execution, + _test_java_test_sets_securiry_manager_property_jdk17, + _test_one_version_check_java_test, + _test_one_version_check_disabled_for_java_test, ], ) diff --git a/test/java/common/rules/merge_attrs_tests.bzl b/test/java/common/rules/merge_attrs_tests.bzl index 84b340e3..bea71adc 100644 --- a/test/java/common/rules/merge_attrs_tests.bzl +++ b/test/java/common/rules/merge_attrs_tests.bzl @@ -1,4 +1,4 @@ -"""Tests for merge_attrsfunction""" +"""Tests for merge_attrs function""" load("@bazel_skylib//lib:unittest.bzl", "asserts", "unittest") load( diff --git a/test/java/private/android_support_tests.bzl b/test/java/private/android_support_tests.bzl index 95596de2..8f9bea64 100644 --- a/test/java/private/android_support_tests.bzl +++ b/test/java/private/android_support_tests.bzl @@ -15,7 +15,8 @@ load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") load("@rules_testing//lib:util.bzl", "util") -load("//java:defs.bzl", "java_library", "java_plugin") +load("//java:java_library.bzl", "java_library") +load("//java:java_plugin.bzl", "java_plugin") load("//java/common:java_info.bzl", "JavaInfo") load("//java/private:android_support.bzl", "android_support") # buildifier: disable=bzl-visibility load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") diff --git a/test/java/testutil/cc_info_subject.bzl b/test/java/testutil/cc_info_subject.bzl index 2d7dca12..b50ff2e6 100644 --- a/test/java/testutil/cc_info_subject.bzl +++ b/test/java/testutil/cc_info_subject.bzl @@ -22,6 +22,7 @@ def _new_cc_info_linking_context_subject(cc_info, meta): public = struct( equals = lambda other: _cc_info_linking_context_equals(self.actual, other, self.meta), library_files = lambda: _new_library_files_subject(self.actual, self.meta), + static_library_files = lambda: _new_static_library_files_subject(self.actual, self.meta), ) return public @@ -43,6 +44,17 @@ def _new_library_files_subject(linking_context, meta): meta = meta.derive("library_files"), ) +def _new_static_library_files_subject(linking_context, meta): + static_libraries = [] + for input in linking_context.linker_inputs.to_list(): + for lib in input.libraries: + if lib.static_library: + static_libraries.append(lib.static_library) + return subjects.depset_file( + depset(static_libraries), + meta = meta.derive("static_library_files"), + ) + def _cc_info_linking_context_equals(actual, expected, meta): if actual == expected: return @@ -87,6 +99,7 @@ def _get_singleton(seq): return seq[0] cc_info_subject = struct( + new_from_cc_info = _new_cc_info_subject, new_from_java_info = lambda java_info, meta: _new_cc_info_subject(java_info.cc_link_params_info, meta.derive("cc_link_params_info")), libraries_to_link = _new_cc_info_libraries_to_link_subject, ) diff --git a/test/java/testutil/java_info_subject.bzl b/test/java/testutil/java_info_subject.bzl index e9242436..9a0fb533 100644 --- a/test/java/testutil/java_info_subject.bzl +++ b/test/java/testutil/java_info_subject.bzl @@ -27,6 +27,7 @@ def _new_java_info_subject(java_info, meta): transitive_source_jars_list = lambda: subjects.collection(java_info.transitive_source_jars.to_list(), self.meta.derive("transitive_source_jars.to_list()")), runtime_output_jars = lambda: subjects.depset_file(java_info.runtime_output_jars, self.meta.derive("runtime_output_jars")), module_flags = lambda: _new_java_module_flags_subject(self.actual, self.meta), + is_neverlink = lambda: subjects.bool(getattr(java_info, "_neverlink", False), self.meta.derive("_neverlink")), ) return public @@ -56,9 +57,10 @@ def _new_java_compilation_info_subject(java_info, meta): ) public = struct( compilation_classpath = lambda: subjects.depset_file(self.actual.compilation_classpath, self.meta.derive("compilation_classpath")), + boot_classpath = lambda: subjects.depset_file(self.actual.boot_classpath, self.meta.derive("boot_classpath")), runtime_classpath = lambda: subjects.depset_file(self.actual.runtime_classpath, self.meta.derive("runtime_classpath")), runtime_classpath_list = lambda: subjects.collection(self.actual.runtime_classpath.to_list(), self.meta.derive("runtime_classpath.to_list()"), format = True), - javac_options = lambda: subjects.collection(helper.tokenize_javacopts(opts = self.actual.javac_options), self.meta.derive("javac_options")), + javac_options = lambda: subjects.collection(helper.tokenize_javacopts(opts = self.actual.javac_options), self.meta.derive("javac_options"), format = True), ) return public @@ -97,6 +99,7 @@ def _new_java_outputs_subject(java_output, meta): source_jars = lambda: subjects.depset_file(java_output.source_jars if hasattr(java_output.source_jars, "to_list") else depset(java_output.source_jars), meta.derive("source_jars")), jdeps = lambda: subjects.file(java_output.jdeps, meta.derive("jdeps")), compile_jdeps = lambda: subjects.file(java_output.compile_jdeps, meta.derive("compile_jdeps")), + manifest_proto = lambda: subjects.file(java_output.manifest_proto, meta.derive("manifest_proto")), native_headers_jar = lambda: subjects.file(java_output.native_headers_jar, meta.derive("native_headers_jar")), ) return public diff --git a/test/java/testutil/java_runtime_info_subject.bzl b/test/java/testutil/java_runtime_info_subject.bzl index ef5bdf92..bb6ae52c 100644 --- a/test/java/testutil/java_runtime_info_subject.bzl +++ b/test/java/testutil/java_runtime_info_subject.bzl @@ -3,6 +3,7 @@ load("@rules_testing//lib:truth.bzl", "subjects", "truth") load("@rules_testing//lib:util.bzl", "TestingAspectInfo") load("//java/common:java_common.bzl", "java_common") +load(":cc_info_subject.bzl", "cc_info_subject") def _new_java_runtime_info_subject(java_runtime_info, meta): self = struct( @@ -10,10 +11,19 @@ def _new_java_runtime_info_subject(java_runtime_info, meta): meta = meta.derive("JavaRuntimeInfo"), ) public = struct( + hermetic_static_libs = lambda: _new_hermetic_static_libs_subject(self.actual.hermetic_static_libs, self.meta.derive("hermetic_static_libs")), java_home = lambda: _new_path_string_subject(self.actual.java_home, self.meta.derive("java_home")), java_home_runfiles_path = lambda: _new_path_string_subject(self.actual.java_home_runfiles_path, self.meta.derive("java_home_runfiles_path")), java_executable_exec_path = lambda: _new_path_string_subject(self.actual.java_executable_exec_path, self.meta.derive("java_executable_exec_path")), java_executable_runfiles_path = lambda: _new_path_string_subject(self.actual.java_executable_runfiles_path, self.meta.derive("java_executable_runfiles_path")), + files = lambda: subjects.depset_file(self.actual.files, self.meta.derive("files")), + lib_ct_sym = lambda: subjects.file(self.actual.lib_ct_sym, self.meta.derive("lib_ct_sym")), + ) + return public + +def _new_hermetic_static_libs_subject(hermetic_static_libs, meta): + public = struct( + singleton = lambda: cc_info_subject.new_from_cc_info(_get_singleton(hermetic_static_libs), meta.derive("cc_info")), ) return public @@ -40,10 +50,16 @@ def _from_target(env, target): "name": target.label.name, "package": target.label.package, "bindir": target[TestingAspectInfo].bin_path, + "gendir": env.ctx.configuration.genfiles_dir.path, }, ), ) +def _get_singleton(seq): + if len(seq) != 1: + fail("expected singleton, got:", seq) + return seq[0] + java_runtime_info_subject = struct( new = _new_java_runtime_info_subject, from_target = _from_target, diff --git a/test/java/testutil/java_toolchain_info_subject.bzl b/test/java/testutil/java_toolchain_info_subject.bzl index af6934b1..31afe59d 100644 --- a/test/java/testutil/java_toolchain_info_subject.bzl +++ b/test/java/testutil/java_toolchain_info_subject.bzl @@ -3,9 +3,31 @@ load("@rules_testing//lib:truth.bzl", "subjects") load("//java/common:java_common.bzl", "java_common") +def _new_java_builder_subject(tool_info, meta): + return subjects.struct( + struct( + data = [f.path for f in tool_info.data.to_list()], + jvm_opts = tool_info.jvm_opts.to_list(), + ), + meta = meta, + attrs = { + "data": lambda values, *, meta: subjects.collection(values, meta = meta, format = True), + "jvm_opts": lambda values, *, meta: subjects.collection(values, meta = meta, format = True), + }, + ) + def _new_java_toolchain_info_subject(info, meta): public = struct( jacocorunner = lambda: subjects.file(info.jacocorunner.executable, meta.derive("jacocorunner.executable")), + timezone_data = lambda: subjects.file(info._timezone_data, meta.derive("_timezone_data")), + header_compiler_builtin_processors = lambda: subjects.collection(info._header_compiler_builtin_processors.to_list(), meta.derive("_header_compiler_builtin_processors")), + reduced_classpath_incompatible_processors = lambda: subjects.collection(info._reduced_classpath_incompatible_processors.to_list(), meta.derive("_reduced_classpath_incompatible_processors")), + javabuilder = lambda: _new_java_builder_subject(info._javabuilder, meta.derive("_javabuilder")), + label = lambda: subjects.label(info.label, meta.derive("label")), + # TODO: hvd - Give label_subject predicate matching support so we don't need this str_subject variant. + label_str = lambda: subjects.str(str(info.label), meta.derive("label_str")), + default_javacopts = lambda: subjects.collection(info._javacopts_list, meta.derive("default_javacopts")), + default_javacopts_depset = lambda: subjects.collection(info._javacopts.to_list(), meta.derive("default_javacopts_depset")), ) return public diff --git a/test/java/testutil/javac_action_subject.bzl b/test/java/testutil/javac_action_subject.bzl index 0a14c777..a887d689 100644 --- a/test/java/testutil/javac_action_subject.bzl +++ b/test/java/testutil/javac_action_subject.bzl @@ -4,10 +4,10 @@ load("@rules_testing//lib:truth.bzl", "subjects", "truth") load("@rules_testing//lib:util.bzl", "TestingAspectInfo") def _new_javac_action_subject(env, target, output): - action = env.expect.that_target(target).action_generating(output).actual + action_subject = env.expect.that_target(target).action_generating(output) self = struct( - actual = action, - parsed_flags = _parse_flags(action.argv), + actual = action_subject.actual, + parsed_flags = _parse_flags(action_subject.actual.argv), meta = truth.expect(env).meta.derive( "Javac", format_str_kwargs = { @@ -17,8 +17,29 @@ def _new_javac_action_subject(env, target, output): }, ), ) + public = struct( - direct_dependencies = lambda: subjects.collection(self.parsed_flags["--direct_dependencies"], self.meta.derive("--direct_dependencies"), format = True), + direct_dependencies = lambda: _create_subject_for_flag("--direct_dependencies", self.parsed_flags, self.meta), + deps_artifacts = lambda: _create_subject_for_flag("--deps_artifacts", self.parsed_flags, self.meta), + javacopts = lambda: _create_subject_for_flag("--javacopts", self.parsed_flags, self.meta), + jar = lambda: _create_subject_for_flag("-jar", self.parsed_flags, self.meta), + # An unset --strict_java_deps is equivalent to "OFF". + strict_java_deps = lambda: _create_subject_for_flag("--strict_java_deps", self.parsed_flags, self.meta, default = ["OFF"]), + sources = lambda: _create_subject_for_flag("--sources", self.parsed_flags, self.meta), + resources = lambda: _create_subject_for_flag("--resources", self.parsed_flags, self.meta), + classpath = lambda: _create_subject_for_flag("--classpath", self.parsed_flags, self.meta), + bootclasspath = lambda: _create_subject_for_flag("--bootclasspath", self.parsed_flags, self.meta), + system = lambda: _create_subject_for_flag("--system", self.parsed_flags, self.meta), + generated_sources_output = lambda: _create_subject_for_flag("--generated_sources_output", self.parsed_flags, self.meta), + processorpath = lambda: _create_subject_for_flag("--processorpath", self.parsed_flags, self.meta), + processors = lambda: _create_subject_for_flag("--processors", self.parsed_flags, self.meta, default = []), + target_label = lambda: _create_subject_for_flag("--target_label", self.parsed_flags, self.meta), + executable_file_name = lambda: subjects.str(action_subject.actual.argv[0], self.meta), + inputs = action_subject.inputs, + outputs = lambda: subjects.collection([o.short_path for o in action_subject.actual.outputs.to_list()], self.meta.derive("outputs()"), format = True), + argv = action_subject.argv, + mnemonic = action_subject.mnemonic, + native_header_output = lambda: _create_subject_for_flag("--native_header_output", self.parsed_flags, self.meta), ) return public @@ -28,7 +49,12 @@ def _parse_flags(argv): for idx, arg in enumerate(argv): if idx == 0: continue # java command - if arg.startswith("-"): + + if current_flag_name == "--javacopts" and arg == "--": + current_flag_name = None + continue + + if arg.startswith("-") and current_flag_name != "--javacopts": if "=" in arg: parts = arg.split("=", 1) flag_values.setdefault(parts[0], []).append(parts[1]) @@ -43,6 +69,10 @@ def _parse_flags(argv): return flag_values +def _create_subject_for_flag(flag_name, parsed_flags, meta, default = None): + """Helper to create a collection subject for a given flag.""" + return subjects.collection(parsed_flags.get(flag_name, default), meta.derive(flag_name), format = True) + javac_action_subject = struct( of = _new_javac_action_subject, parse_flags = _parse_flags, # exposed for testing this method itself diff --git a/test/java/testutil/javac_action_subject_tests.bzl b/test/java/testutil/javac_action_subject_tests.bzl index eba3f76b..dc8f3f47 100644 --- a/test/java/testutil/javac_action_subject_tests.bzl +++ b/test/java/testutil/javac_action_subject_tests.bzl @@ -18,6 +18,7 @@ def _parse_flags_test_impl(ctx): "JavaBuilder_deploy.jar", "--output", "blaze-out/k8/bin/pkg/libfoo.jar", + "--javacopts", "-source", "21", "-target", @@ -34,6 +35,12 @@ def _parse_flags_test_impl(ctx): "--classpath", "pkg/bar-hjar.jar", "other/pkg/baz.jar", + "--processors", + "com.example.process.stuff", + "com.example.process.other", + "--deps_artifacts", + "pkg/dep1.jdeps", + "pkg/dep2.jdeps", ]) asserts.equals(env, { "-Xmx1g": [], @@ -49,15 +56,22 @@ def _parse_flags_test_impl(ctx): ], "-jar": ["JavaBuilder_deploy.jar"], "--output": ["blaze-out/k8/bin/pkg/libfoo.jar"], - "-source": ["21"], - "-target": ["17"], - "-g": [], - "-parameters": [], - "-sourcepath": [":"], - "-Xmaxerrs": ["123"], - "--": [], + "--javacopts": [ + "-source", + "21", + "-target", + "17", + "-g", + "-parameters", + "-sourcepath", + ":", + "-Xmaxerrs", + "123", + ], "--strict_java_deps": ["ERROR"], "--classpath": ["pkg/bar-hjar.jar", "other/pkg/baz.jar"], + "--processors": ["com.example.process.stuff", "com.example.process.other"], + "--deps_artifacts": ["pkg/dep1.jdeps", "pkg/dep2.jdeps"], }, flags) return unittest.end(env) diff --git a/test/java/testutil/mock_cc_toolchain.bzl b/test/java/testutil/mock_cc_toolchain.bzl new file mode 100644 index 00000000..6680938d --- /dev/null +++ b/test/java/testutil/mock_cc_toolchain.bzl @@ -0,0 +1,56 @@ +"""Fake cc_toolchain for testing arbitrary --platforms/--cpu""" + +load("@rules_cc//cc:find_cc_toolchain.bzl", "CC_TOOLCHAIN_TYPE") +load("@rules_cc//cc/common:cc_common.bzl", "cc_common") +load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") +load("@rules_cc//cc/toolchains:cc_toolchain_config_info.bzl", "CcToolchainConfigInfo") + +def _mock_config_impl(ctx): + return [ + cc_common.create_cc_toolchain_config_info( + ctx = ctx, + toolchain_identifier = ctx.attr.id, + compiler = "nothing", + # These are deprecated but are mandatory parameters for older Bazel versions. + target_system_name = "deprecated_system_name", + target_cpu = "deprecated_cpu", + target_libc = "deprecated_libc", + ), + ] + +_mock_config = rule( + implementation = _mock_config_impl, + attrs = { + "id": attr.string(mandatory = True), + }, + provides = [CcToolchainConfigInfo], +) + +def mock_cc_toolchain(*, name, cpu, os, **kwargs): + _mock_config( + name = name + "_config", + id = cpu + "-" + os, + **kwargs + ) + cc_toolchain( + name = name + "_impl", + all_files = ":nothing", + as_files = ":nothing", + compiler_files = ":nothing", + dwp_files = ":nothing", + linker_files = ":nothing", + objcopy_files = ":nothing", + strip_files = ":nothing", + toolchain_config = name + "_config", + **kwargs + ) + native.toolchain( + name = name, + toolchain = name + "_impl", + toolchain_type = CC_TOOLCHAIN_TYPE, + target_compatible_with = [ + "@platforms//cpu:" + cpu, + "@platforms//os:" + os, + ], + **kwargs + ) diff --git a/test/java/testutil/mock_java_toolchain.bzl b/test/java/testutil/mock_java_toolchain.bzl new file mode 100644 index 00000000..aae0afde --- /dev/null +++ b/test/java/testutil/mock_java_toolchain.bzl @@ -0,0 +1,72 @@ +"""Fake java toolchains for testing""" + +load("//java/common:java_semantics.bzl", "semantics") +load("//java/toolchains:java_runtime.bzl", _java_runtime_rule = "java_runtime") +load("//java/toolchains:java_toolchain.bzl", "java_toolchain") + +# buildifier: disable=function-docstring +def mock_java_toolchain( + *, + name, + singlejar = "singlejar", + javabuilder = "JavaBuilder_deploy.jar", + header_compiler = "turbine_canary_deploy.jar", + header_compiler_direct = "turbine_direct", + ijar = "ijar", + genclass = "genclass", + java_runtime = None, + oneversion = None, + oneversion_allowlist = None, + oneversion_allowlist_for_tests = None, + tags = None, # for util.helper_target + **kwargs): + if not java_runtime: + java_runtime = name + "_runtime" + _java_runtime_rule(name = java_runtime) + one_version_args = { + "oneversion": oneversion, + "oneversion_allowlist": oneversion_allowlist, + "oneversion_allowlist_for_tests": oneversion_allowlist_for_tests, + } if semantics.java_toolchain_supports_one_version else {} + java_toolchain( + name = name + "_java", + javabuilder = javabuilder, + singlejar = singlejar, + header_compiler = header_compiler, + header_compiler_direct = header_compiler_direct, + ijar = ijar, + java_runtime = java_runtime, + genclass = genclass, + tags = tags, + **(kwargs | one_version_args) + ) + native.toolchain( + name = name, + toolchain = name + "_java", + toolchain_type = semantics.JAVA_TOOLCHAIN_TYPE, + tags = tags, + ) + +# buildifier: disable=function-docstring +def mock_java_runtime_toolchain( + *, + name, + srcs = [], + java_home = None, + java = None, + version = None, + **kwargs): + _java_runtime_rule( + name = name + "_runtime", + srcs = srcs, + java_home = java_home, + java = java, + version = version, + **kwargs + ) + native.toolchain( + name = name, + toolchain = name + "_runtime", + toolchain_type = semantics.JAVA_RUNTIME_TOOLCHAIN_TYPE, + **kwargs + ) diff --git a/test/java/testutil/mock_test_toolchain.bzl b/test/java/testutil/mock_test_toolchain.bzl new file mode 100644 index 00000000..cf73145e --- /dev/null +++ b/test/java/testutil/mock_test_toolchain.bzl @@ -0,0 +1,29 @@ +"""Fake test toolchain for testing arbitrary --platforms""" + +load("@bazel_features//:features.bzl", "bazel_features") +load("@rules_testing//lib:util.bzl", "util") +load("//java/common:java_semantics.bzl", "semantics") + +def mock_test_toolchains(name, cpu, os): + """Creates and returns a list of mock test toolchains for the given cpu and os if they're required. + + Args: + name: The name of the toolchain. + cpu: The cpu for toolchain should be compatible with. + os: The os the toolchain should be compatible with. + Returns: + A list of toolchain targets. + """ + if not bazel_features.toolchains.has_default_test_toolchain_type: + return [] + util.helper_target( + rule = native.toolchain, + name = name, + toolchain_type = Label(semantics.TOOLS_TEST_DEFAULT_TEST_TOOLCHAIN_TYPE), + toolchain = Label(semantics.TOOLS_TEST_EMPTY_TOOLCHAIN), + target_compatible_with = [ + "@platforms//os:" + os, + "@platforms//cpu:" + cpu, + ], + ) + return [native.package_relative_label(name)] diff --git a/test/java/testutil/rules/custom_java_info_rule.bzl b/test/java/testutil/rules/custom_java_info_rule.bzl index 3b61473a..e9a47918 100644 --- a/test/java/testutil/rules/custom_java_info_rule.bzl +++ b/test/java/testutil/rules/custom_java_info_rule.bzl @@ -61,6 +61,8 @@ def _impl(ctx): generated_source_jar = ctx.file.generated_source_jar, native_headers_jar = ctx.file.native_headers_jar, manifest_proto = ctx.file.manifest_proto, + add_exports = ctx.attr.add_exports, + add_opens = ctx.attr.add_opens, ), ] @@ -86,6 +88,8 @@ custom_java_info_rule = rule( "pack_sources": attr.bool(default = False), "stamp_jar": attr.bool(default = False), "compile_jar": attr.label(allow_single_file = True), + "add_exports": attr.string_list(), + "add_opens": attr.string_list(), }, toolchains = [semantics.JAVA_TOOLCHAIN_TYPE], ) diff --git a/test/java/testutil/rules/custom_library.bzl b/test/java/testutil/rules/custom_library.bzl index 024c05d9..5ef3ca03 100644 --- a/test/java/testutil/rules/custom_library.bzl +++ b/test/java/testutil/rules/custom_library.bzl @@ -1,5 +1,6 @@ """Helper rule for testing compilation with default parameter values""" +load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") load("//java/common:java_common.bzl", "java_common") load("//java/common:java_info.bzl", "JavaInfo") load("//java/common:java_plugin_info.bzl", "JavaPluginInfo") @@ -9,6 +10,7 @@ def _custom_library_impl(ctx): output_jar = ctx.actions.declare_file("lib" + ctx.label.name + ".jar") deps = [dep[JavaInfo] for dep in ctx.attr.deps] runtime_deps = [dep[JavaInfo] for dep in ctx.attr.runtime_deps] + native_libraries = [dep[CcInfo] for dep in ctx.attr.ccdeps] compilation_provider = java_common.compile( ctx, source_files = ctx.files.srcs, @@ -21,6 +23,8 @@ def _custom_library_impl(ctx): plugins = [p[JavaPluginInfo] for p in ctx.attr.plugins], javac_opts = ctx.attr.javac_opts, java_toolchain = semantics.find_java_toolchain(ctx), + enable_annotation_processing = ctx.attr.enable_annotation_processing, + native_libraries = native_libraries, ) return [DefaultInfo(files = depset([output_jar])), compilation_provider] @@ -31,10 +35,12 @@ custom_library = rule( "source_jars": attr.label_list(allow_files = [".jar"]), "deps": attr.label_list(), "runtime_deps": attr.label_list(), + "ccdeps": attr.label_list(providers = [CcInfo]), "exports": attr.label_list(), "plugins": attr.label_list(), "javac_opts": attr.string_list(), "neverlink": attr.bool(), + "enable_annotation_processing": attr.bool(default = True), }, toolchains = [semantics.JAVA_TOOLCHAIN_TYPE], fragments = ["java"], diff --git a/test/java/testutil/rules/custom_library_with_strict_java_deps_provider.bzl b/test/java/testutil/rules/custom_library_with_strict_java_deps_provider.bzl new file mode 100644 index 00000000..3a0f66a7 --- /dev/null +++ b/test/java/testutil/rules/custom_library_with_strict_java_deps_provider.bzl @@ -0,0 +1,15 @@ +"""Custom libraty that reads --strict_java_deps and returns it from a provider.""" + +StrictJavaDepsInfo = provider( + doc = "Provides args.strict_java_deps for testing", + fields = ["strict_java_deps"], +) + +def _impl(ctx): + return [StrictJavaDepsInfo(strict_java_deps = ctx.fragments.java.strict_java_deps)] + +custom_library_with_strict_java_deps_provider = rule( + implementation = _impl, + attrs = {}, + fragments = ["java"], +) diff --git a/test/java/testutil/rules/custom_library_with_wrong_java_toolchain_type.bzl b/test/java/testutil/rules/custom_library_with_wrong_java_toolchain_type.bzl new file mode 100644 index 00000000..73b4a7f9 --- /dev/null +++ b/test/java/testutil/rules/custom_library_with_wrong_java_toolchain_type.bzl @@ -0,0 +1,24 @@ +"""Custom rule to test java_common.compile(java_toolchain = ...) expects JavaToolchainInfo""" + +load("//java/common:java_common.bzl", "java_common") +load("//java/common:java_semantics.bzl", "semantics") + +def _impl(ctx): + output_jar = ctx.actions.declare_file("lib" + ctx.label.name + ".jar") + return java_common.compile( + ctx, + source_files = ctx.files.srcs, + output = output_jar, + java_toolchain = ctx.attr._java_toolchain[platform_common.ToolchainInfo], + ) + +custom_library_with_wrong_java_toolchain_type = rule( + implementation = _impl, + attrs = { + "srcs": attr.label_list(allow_files = [".java"]), + "deps": attr.label_list(), + "_java_toolchain": attr.label(default = semantics.JAVA_TOOLCHAIN_LABEL), + }, + toolchains = [semantics.JAVA_TOOLCHAIN_TYPE], + fragments = ["java"], +) diff --git a/test/java/testutil/rules/custom_library_with_wrong_plugins_type.bzl b/test/java/testutil/rules/custom_library_with_wrong_plugins_type.bzl index 12535307..dc58cee1 100644 --- a/test/java/testutil/rules/custom_library_with_wrong_plugins_type.bzl +++ b/test/java/testutil/rules/custom_library_with_wrong_plugins_type.bzl @@ -1,6 +1,7 @@ """Custom rule to test java_common.compile(plugins = ...) expects JavaPluginInfo""" -load("//java:defs.bzl", "JavaInfo", "java_common") +load("//java/common:java_common.bzl", "java_common") +load("//java/common:java_info.bzl", "JavaInfo") load("//java/common:java_semantics.bzl", "semantics") def _impl(ctx): diff --git a/test/java/testutil/rules/java_info_merge.bzl b/test/java/testutil/rules/java_info_merge.bzl new file mode 100644 index 00000000..e31201d9 --- /dev/null +++ b/test/java/testutil/rules/java_info_merge.bzl @@ -0,0 +1,17 @@ +"""Helper rule for testing java_common.merge""" + +load("//java/common:java_common.bzl", "java_common") +load("//java/common:java_info.bzl", "JavaInfo") + +def _impl(ctx): + java_infos = [dep[JavaInfo] for dep in ctx.attr.deps] + merged_info = java_common.merge(java_infos) + return [merged_info] + +java_info_merge_rule = rule( + implementation = _impl, + attrs = { + "deps": attr.label_list(providers = [JavaInfo]), + }, + provides = [JavaInfo], +) diff --git a/test/java/testutil/rules/private_api_usage.bzl b/test/java/testutil/rules/private_api_usage.bzl new file mode 100644 index 00000000..9ceaf826 --- /dev/null +++ b/test/java/testutil/rules/private_api_usage.bzl @@ -0,0 +1,57 @@ +"""Helper rules to test private API usage""" + +load("//java/common:java_common.bzl", "java_common") +load("//java/common:java_info.bzl", "JavaInfo") +load("//java/common:java_semantics.bzl", "semantics") + +_PRIVATE_ATTR_ATTRS = { + "private_attr_name": attr.string(mandatory = True), +} + +def _private_compile_api_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name + ".jar") + java_common.compile( + ctx = ctx, + output = out, + java_toolchain = semantics.find_java_toolchain(ctx), + **{ctx.attr.private_attr_name: "does_not_matter"} + ) + return [] + +private_compile_api_usage = rule( + _private_compile_api_impl, + attrs = _PRIVATE_ATTR_ATTRS, + fragments = ["java"], + toolchains = [semantics.JAVA_TOOLCHAIN_TYPE], +) + +def _private_merge_api_impl(ctx): + out = ctx.actions.declare_file(ctx.label.name + ".jar") + info = JavaInfo(output_jar = out, compile_jar = out) + java_common.merge( + providers = [info], + **{ctx.attr.private_attr_name: "does_not_matter"} + ) + return [] + +private_merge_api_usage = rule( + _private_merge_api_impl, + attrs = _PRIVATE_ATTR_ATTRS, + fragments = ["java"], +) + +def _private_run_ijar_api_impl(ctx): + java_common.run_ijar( + ctx.actions, + java_toolchain = semantics.find_java_toolchain(ctx), + jar = ctx.actions.declare_file(ctx.label.name + "_ijar.jar"), + **{ctx.attr.private_attr_name: "does_not_matter"} + ) + return [] + +private_run_ijar_api_usage = rule( + _private_run_ijar_api_impl, + attrs = _PRIVATE_ATTR_ATTRS, + fragments = ["java"], + toolchains = [semantics.JAVA_TOOLCHAIN_TYPE], +) diff --git a/test/java/testutil/rules/template_var_info_rule.bzl b/test/java/testutil/rules/template_var_info_rule.bzl new file mode 100644 index 00000000..ebdc86cc --- /dev/null +++ b/test/java/testutil/rules/template_var_info_rule.bzl @@ -0,0 +1,13 @@ +"""Test rule to provide TemplateVariableInfo""" + +def _template_var_info_rule_impl(ctx): + return [ + platform_common.TemplateVariableInfo(ctx.attr.vars), + ] + +template_var_info_rule = rule( + _template_var_info_rule_impl, + attrs = { + "vars": attr.string_dict(default = {}), + }, +) diff --git a/test/java/toolchains/BUILD b/test/java/toolchains/BUILD index 4ebe1f2d..1d7af21f 100644 --- a/test/java/toolchains/BUILD +++ b/test/java/toolchains/BUILD @@ -6,3 +6,5 @@ package(default_applicable_licenses = ["@rules_java//:license"]) java_runtime_tests(name = "java_runtime_tests") java_toolchain_tests(name = "java_toolchain_tests") + +exports_files(["java_runtime.src"]) diff --git a/test/java/toolchains/java_runtime_tests.bzl b/test/java/toolchains/java_runtime_tests.bzl index 4f1ec88a..94d067ea 100644 --- a/test/java/toolchains/java_runtime_tests.bzl +++ b/test/java/toolchains/java_runtime_tests.bzl @@ -1,17 +1,19 @@ """Tests for the java_runtime rule""" +load("@rules_cc//cc:defs.bzl", "cc_import") load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching", "subjects") load("@rules_testing//lib:util.bzl", "util") -load("//java/common:java_semantics.bzl", "semantics") load("//java/toolchains:java_runtime.bzl", "java_runtime") load("//test/java/testutil:java_runtime_info_subject.bzl", "java_runtime_info_subject") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_runtime_toolchain") load("//test/java/testutil:rules/forward_java_runtime_info.bzl", "java_runtime_info_forwarding_rule") load("//toolchains:java_toolchain_alias.bzl", "java_runtime_alias") def _test_with_absolute_java_home(name): util.helper_target( - java_runtime, - name = name + "/jvm", + mock_java_runtime_toolchain, + name = name + "/java_runtime_toolchain", srcs = [], java_home = "/foo/bar", ) @@ -24,12 +26,6 @@ def _test_with_absolute_java_home(name): name = name + "/r", java_runtime = name + "/alias", ) - util.helper_target( - native.toolchain, - name = name + "/java_runtime_toolchain", - toolchain = name + "/jvm", - toolchain_type = semantics.JAVA_RUNTIME_TOOLCHAIN_TYPE, - ) analysis_test( name = name, @@ -38,8 +34,6 @@ def _test_with_absolute_java_home(name): config_settings = { "//command_line_option:extra_toolchains": [Label(name + "/java_runtime_toolchain")], }, - # Bazel 6 doesn't accept Label's for the transition above - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_with_absolute_java_home_impl(env, target): @@ -52,8 +46,8 @@ def _test_with_absolute_java_home_impl(env, target): def _test_with_hermetic_java_home(name): util.helper_target( - java_runtime, - name = name + "/jvm", + mock_java_runtime_toolchain, + name = name + "/java_runtime_toolchain", srcs = [], java_home = "foo/bar", ) @@ -66,12 +60,6 @@ def _test_with_hermetic_java_home(name): name = name + "/r", java_runtime = name + "/alias", ) - util.helper_target( - native.toolchain, - name = name + "/java_runtime_toolchain", - toolchain = name + "/jvm", - toolchain_type = semantics.JAVA_RUNTIME_TOOLCHAIN_TYPE, - ) analysis_test( name = name, @@ -80,8 +68,6 @@ def _test_with_hermetic_java_home(name): config_settings = { "//command_line_option:extra_toolchains": [Label(name + "/java_runtime_toolchain")], }, - # Bazel 6 doesn't accept Label's for the transition above - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_with_hermetic_java_home_impl(env, target): @@ -101,8 +87,8 @@ def _test_with_generated_java_executable(name): output_to_bindir = True, ) util.helper_target( - java_runtime, - name = name + "/jvm", + mock_java_runtime_toolchain, + name = name + "/java_runtime_toolchain", srcs = [], java = "foo/bar/bin/java", ) @@ -115,12 +101,6 @@ def _test_with_generated_java_executable(name): name = name + "/r", java_runtime = name + "/alias", ) - util.helper_target( - native.toolchain, - name = name + "/java_runtime_toolchain", - toolchain = name + "/jvm", - toolchain_type = semantics.JAVA_RUNTIME_TOOLCHAIN_TYPE, - ) analysis_test( name = name, @@ -129,8 +109,6 @@ def _test_with_generated_java_executable(name): config_settings = { "//command_line_option:extra_toolchains": [Label(name + "/java_runtime_toolchain")], }, - # Bazel 6 doesn't accept Label's for the transition above - attr_values = {"tags": ["min_bazel_7"]}, ) def _test_with_generated_java_executable_impl(env, target): @@ -141,6 +119,288 @@ def _test_with_generated_java_executable_impl(env, target): assert_info.java_executable_exec_path().starts_with("{bindir}/{package}/foo/bar/bin/java") assert_info.java_executable_runfiles_path().starts_with("{package}/foo/bar/bin/java") +def _test_runtime_alias(name): + util.helper_target( + java_runtime_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_runtime_alias_impl, + target = name + "/alias", + ) + +def _test_runtime_alias_impl(env, target): + env.expect.that_target(target).has_provider(platform_common.ToolchainInfo) + env.expect.that_target(target).has_provider(platform_common.TemplateVariableInfo) + +def _test_java_runtime_simple(name): + util.helper_target( + java_runtime, + name = name + "/jvm-foo", + srcs = [ + "foo/a", + "foo/b", + ], + java_home = "foo", + ) + + analysis_test( + name = name, + impl = _test_java_runtime_simple_impl, + target = name + "/jvm-foo", + ) + +def _test_java_runtime_simple_impl(env, target): + java_runtime_info_subject.from_target(env, target).files().contains_exactly([ + "{package}/foo/a", + "{package}/foo/b", + ]) + env.expect.that_target(target).data_runfiles().contains_exactly([ + "{workspace}/{package}/foo/a", + "{workspace}/{package}/foo/b", + ]) + +def _test_absolute_java_home_with_srcs(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + srcs = ["dummy.txt"], + java_home = "/absolute/path", + ) + + analysis_test( + name = name, + impl = _test_absolute_java_home_with_srcs_impl, + target = name + "/jvm", + expect_failure = True, + ) + +def _test_absolute_java_home_with_srcs_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("'java_home' with an absolute path requires 'srcs' to be empty."), + ) + +def _test_absolute_java_home_with_java(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java = "bin/java", + java_home = "/absolute/path", + ) + + analysis_test( + name = name, + impl = _test_absolute_java_home_with_java_impl, + target = name + "/jvm", + expect_failure = True, + ) + +def _test_absolute_java_home_with_java_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("'java_home' with an absolute path requires 'java' to be empty."), + ) + +def _test_bin_java_path_name(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java = "java", + ) + + analysis_test( + name = name, + impl = _test_bin_java_path_name_impl, + target = name + "/jvm", + expect_failure = True, + ) + +def _test_bin_java_path_name_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("the path to 'java' must end in 'bin/java'."), + ) + +def _test_absolute_java_home(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java_home = "/absolute/path", + ) + + analysis_test( + name = name, + impl = _test_absolute_java_home_impl, + target = name + "/jvm", + ) + +def _test_absolute_java_home_impl(env, target): + java_runtime_info_subject.from_target(env, target).java_home().equals("/absolute/path") + +def _test_relative_java_home(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java_home = "b/c", + ) + + analysis_test( + name = name, + impl = _test_relative_java_home_impl, + target = name + "/jvm", + ) + +def _test_relative_java_home_impl(env, target): + java_runtime_info_subject.from_target(env, target).java_home().equals("{package}/b/c") + +def _test_java_home_with_invalid_make_variables(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java_home = "/opt/$(WTF)", + ) + + analysis_test( + name = name, + impl = _test_java_home_with_invalid_make_variables_impl, + target = name + "/jvm", + expect_failure = True, + ) + +def _test_java_home_with_invalid_make_variables_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("$(WTF) not defined"), + ) + +def _test_make_variables(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java_home = "/foo/bar", + ) + + analysis_test( + name = name, + impl = _test_make_variables_impl, + target = name + "/jvm", + ) + +def _test_make_variables_impl(env, target): + env.expect.that_target(target).provider( + platform_common.TemplateVariableInfo, + ).variables().contains_at_least({"JAVABASE": "/foo/bar"}) + env.expect.that_target(target).provider( + platform_common.TemplateVariableInfo, + ).variables().get("JAVA", factory = subjects.str).starts_with("/foo/bar/bin/java") + +def _test_no_srcs(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + java_home = "/opt/jvm", + ) + + analysis_test( + name = name, + impl = _test_no_srcs_impl, + target = name + "/jvm", + ) + +def _test_no_srcs_impl(env, target): + assert_info = java_runtime_info_subject.from_target(env, target) + assert_info.java_home().equals("/opt/jvm") + assert_info.files().contains_exactly([]) + +def _test_java_home_generated(name): + util.helper_target( + native.genrule, + name = name + "/gen", + outs = ["generated_java_home/bin/java"], + cmd = "touch $@", + ) + util.helper_target( + java_runtime, + name = name + "/jvm", + java = "generated_java_home/bin/java", + java_home = "generated_java_home", + ) + + analysis_test( + name = name, + impl = _test_java_home_generated_impl, + target = name + "/jvm", + ) + +def _test_java_home_generated_impl(env, target): + java_runtime_info_subject.from_target(env, target).java_home().equals( + "{gendir}/{package}/generated_java_home", + ) + +def _test_hermetic_static_libs(name): + util.helper_target( + cc_import, + name = name + "/libs", + static_library = "libStatic.a", + ) + util.helper_target( + java_runtime, + name = name + "/jvm", + lib_modules = name + "/gen_lib_modules", + hermetic_srcs = [name + "/hermetic.properties"], + hermetic_static_libs = [name + "/libs"], + ) + + analysis_test( + name = name, + impl = _test_hermetic_static_libs_impl, + target = name + "/jvm", + ) + +def _test_hermetic_static_libs_impl(env, target): + cc_info = java_runtime_info_subject.from_target(env, target).hermetic_static_libs().singleton() + cc_info.linking_context().static_library_files().contains_exactly(["{package}/libStatic.a"]) + +def _test_implicit_lib_ct_sym(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + srcs = [ + name + "/java", + name + "/jvm/implicit/lib/ct.sym", + ], + ) + analysis_test( + name = name, + impl = _test_implicit_lib_ct_sym_impl, + target = name + "/jvm", + ) + +def _test_implicit_lib_ct_sym_impl(env, target): + java_runtime_info_subject.from_target(env, target).lib_ct_sym().short_path_equals( + "{package}/{name}/implicit/lib/ct.sym", + ) + +def _test_explicit_lib_ct_sym(name): + util.helper_target( + java_runtime, + name = name + "/jvm", + srcs = [ + name + "/java", + name + "/jvm/implicit/lib/ct.sym", + ], + lib_ct_sym = name + "/jvm/explicit/lib/ct.sym", + ) + analysis_test( + name = name, + impl = _test_explicit_lib_ct_sym_impl, + target = name + "/jvm", + ) + +def _test_explicit_lib_ct_sym_impl(env, target): + java_runtime_info_subject.from_target(env, target).lib_ct_sym().short_path_equals( + "{package}/{name}/explicit/lib/ct.sym", + ) + def java_runtime_tests(name): test_suite( name = name, @@ -148,5 +408,19 @@ def java_runtime_tests(name): _test_with_absolute_java_home, _test_with_hermetic_java_home, _test_with_generated_java_executable, + _test_runtime_alias, + _test_java_runtime_simple, + _test_absolute_java_home_with_srcs, + _test_absolute_java_home_with_java, + _test_bin_java_path_name, + _test_absolute_java_home, + _test_relative_java_home, + _test_java_home_with_invalid_make_variables, + _test_make_variables, + _test_no_srcs, + _test_java_home_generated, + _test_hermetic_static_libs, + _test_implicit_lib_ct_sym, + _test_explicit_lib_ct_sym, ], ) diff --git a/test/java/toolchains/java_toolchain_tests.bzl b/test/java/toolchains/java_toolchain_tests.bzl index 378ba910..793de8ea 100644 --- a/test/java/toolchains/java_toolchain_tests.bzl +++ b/test/java/toolchains/java_toolchain_tests.bzl @@ -1,36 +1,91 @@ """Tests for the java_toolchain rule""" load("@rules_testing//lib:analysis_test.bzl", "analysis_test", "test_suite") +load("@rules_testing//lib:truth.bzl", "matching", "subjects") load("@rules_testing//lib:util.bzl", "util") -load("//java/toolchains:java_runtime.bzl", "java_runtime") -load("//java/toolchains:java_toolchain.bzl", "java_toolchain") +load("//java:java_binary.bzl", "java_binary") +load("//java:java_library.bzl", "java_library") +load("//java:java_plugin.bzl", "java_plugin") +load("//java/common:java_common.bzl", "java_common") +load("//test/java/testutil:java_info_subject.bzl", "java_info_subject") load("//test/java/testutil:java_toolchain_info_subject.bzl", "java_toolchain_info_subject") +load("//test/java/testutil:javac_action_subject.bzl", "javac_action_subject") +load("//test/java/testutil:mock_java_toolchain.bzl", "mock_java_toolchain") +load("//toolchains:java_toolchain_alias.bzl", "java_toolchain_alias") -def _declare_java_toolchain(*, name, **kwargs): - if "java_runtime" not in kwargs: - kwargs["java_runtime"] = name + "/runtime" - java_runtime(name = name + "/runtime") +def _test_javac_gets_options(name): util.helper_target( - java_toolchain, + mock_java_toolchain, + name = name + "/toolchain", + javabuilder = name + "/JavaBuilder_deploy.jar", + header_compiler_direct = name + "/turbine_direct", + bootclasspath = [name + "/rt.jar"], + source_version = "6", + target_version = "6", + xlint = ["toto"], + javacopts = ["-Xmaxerrs 500"], + ) + util.helper_target( + java_library, + name = name + "/b", + srcs = ["b.java"], + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + deps = [Label(name + "/b")], + ) + + analysis_test( name = name, - genclass = [kwargs.get("genclass", "default_genclass.jar")], - jacocorunner = kwargs.get("jacocorunner", None), - javabuilder = [kwargs.get("javabuilder", "default_javabuilder.jar")], - java_runtime = kwargs["java_runtime"], - ijar = [kwargs.get("ijar", "default_ijar.jar")], - singlejar = [kwargs.get("singlejar", "default_singlejar.jar")], + impl = _test_javac_gets_options_impl, + targets = { + "a": name + "/a", + "b": name + "/b", + }, + config_settings = { + "//command_line_option:java_header_compilation": "true", + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, ) +def _test_javac_gets_options_impl(env, targets): + assert_javac_action = javac_action_subject.of(env, targets.a, "{package}/lib{name}.jar") + assert_javac_action.javacopts().contains_at_least([ + "-source", + "6", + "-target", + "6", + "-Xlint:toto", + "-Xmaxerrs", + "500", + ]) + assert_javac_action.jar().contains_exactly(["{package}/{test_name}/JavaBuilder_deploy.jar"]) + assert_javac_action.inputs().contains("{package}/{test_name}/rt.jar") + + assert_javac_action.javacopts().not_contains("-g") + + assert_header_action = javac_action_subject.of(env, targets.b, "{package}/lib{name}-hjar.jar") + assert_header_action.argv().contains("{package}/{test_name}/turbine_direct") + def _test_jacocorunner(name): - _declare_java_toolchain( - name = name + "/java_toolchain", + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", jacocorunner = "myjacocorunner.jar", ) - + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) analysis_test( name = name, impl = _test_jacocorunner_impl, - target = name + "/java_toolchain", + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, ) def _test_jacocorunner_impl(env, target): @@ -38,10 +93,684 @@ def _test_jacocorunner_impl(env, target): assert_toolchain.jacocorunner().short_path_equals("{package}/myjacocorunner.jar") +def _test_singlejar_get_command_line(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + ) + util.helper_target( + java_binary, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_singlejar_get_command_line_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + # This crashes in earlier Bazel versions where native rules handled deploy jars differently. + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_singlejar_get_command_line_impl(env, target): + assert_javac_action = javac_action_subject.of(env, target, "{package}/{name}_deploy.jar") + assert_javac_action.executable_file_name().equals(target.label.package + "/singlejar") + +def _test_genclass_get_command_line(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + genclass = name + "/GenClass_deploy.jar", + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + javacopts = ["-processor NOSUCH"], + ) + + analysis_test( + name = name, + impl = _test_genclass_get_command_line_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_genclass_get_command_line_impl(env, target): + assert_javac_action = javac_action_subject.of(env, target, "{package}/lib{name}-gen.jar") + + assert_javac_action.jar().contains_exactly(["{package}/{test_name}/GenClass_deploy.jar"]) + +def _test_timezone_data_is_correct(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + timezone_data = "tzdata.jar", + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_timezone_data_is_correct_impl, + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_timezone_data_is_correct_impl(env, target): + java_toolchain_info_subject.from_target(env, target).timezone_data().short_path_equals( + "{package}/tzdata.jar", + ) + +def _test_java_binary_uses_timezone_data(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + timezone_data = name + "/tzdata.jar", + ) + util.helper_target( + java_binary, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_java_binary_uses_timezone_data_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_java_binary_uses_timezone_data_impl(env, target): + assert_action = javac_action_subject.of(env, target, "{package}/{name}.jar") + assert_action.sources().contains("{package}/{test_name}/tzdata.jar") + assert_action.inputs().contains_predicate(matching.file_basename_equals("tzdata.jar")) + +def _test_ijar_get_command_line(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_ijar_get_command_line_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:java_header_compilation": "false", + }, + ) + +def _test_ijar_get_command_line_impl(env, target): + compile_jar = java_info_subject.from_target(env, target).java_outputs().singleton().compile_jar().actual + env.expect.that_target(target).action_generating(compile_jar.short_path).argv().contains( + "{package}/ijar", + ) + +def _test_no_header_compiler_header_compilation_enabled_fails(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + header_compiler = None, + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_no_header_compiler_header_compilation_enabled_fails_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:java_header_compilation": "true", + }, + expect_failure = True, + ) + +def _test_no_header_compiler_header_compilation_enabled_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("header compilation was requested but it is not supported by the " + + "current Java toolchain"), + ) + +def _test_no_header_compiler_direct_header_compilation_enabled_fails(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + header_compiler_direct = None, + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_no_header_compiler_direct_header_compilation_enabled_fails_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:java_header_compilation": "true", + }, + expect_failure = True, + ) + +def _test_no_header_compiler_direct_header_compilation_enabled_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("header compilation was requested but it is not supported by the " + + "current Java toolchain"), + ) + +def _test_no_header_compiler_header_compilation_disabled_analyzes_successfully(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + header_compiler = None, + ) + util.helper_target( + java_library, + name = name + "/a", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_no_header_compiler_header_compilation_disabled_analyzes_successfully_impl, + target = name + "/a", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:java_header_compilation": "false", + }, + ) + +def _test_no_header_compiler_header_compilation_disabled_analyzes_successfully_impl( + env, # @unused + target): # @unused + # Implicitly succeeds. + pass + +def _test_header_compiler_builtin_processors(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + header_compiler_builtin_processors = ["BuiltinProc1", "BuiltinProc2"], + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_header_compiler_builtin_processors_impl, + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_header_compiler_builtin_processors_impl(env, target): + java_toolchain_info_subject.from_target(env, target).header_compiler_builtin_processors().contains_exactly([ + "BuiltinProc1", + "BuiltinProc2", + ]) + +def _test_reduced_classpath_incompatible_processors(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + reduced_classpath_incompatible_processors = ["IncompatibleProc1", "IncompatibleProc2"], + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_reduced_classpath_incompatible_processors_impl, + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_reduced_classpath_incompatible_processors_impl(env, target): + java_toolchain_info_subject.from_target(env, target).reduced_classpath_incompatible_processors().contains_exactly([ + "IncompatibleProc1", + "IncompatibleProc2", + ]) + +def _test_location_expansion_in_jvm_opts(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + tools = [name + "/jsr305.jar", name + "/javac"], + jvm_opts = [ + "--patch-module=jdk.compiler=$(location " + name + "/javac)", + "--patch-module=java.xml.ws.annotation=$(location " + name + "/jsr305.jar)", + ], + javabuilder_jvm_opts = ["-Xshare:auto"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["a.java"], + ) + + analysis_test( + name = name, + impl = _test_location_expansion_in_jvm_opts_impl, + target = name + "/lib", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_location_expansion_in_jvm_opts_impl(env, target): + assert_javac_action = env.expect.that_target(target).action_generating("{package}/lib{name}.jar") + assert_javac_action.argv().contains("--patch-module=jdk.compiler={package}/{test_name}/javac") + assert_javac_action.argv().contains("--patch-module=java.xml.ws.annotation={package}/{test_name}/jsr305.jar") + assert_javac_action.argv().contains("-Xshare:auto") + assert_javac_action.inputs().contains("{package}/{test_name}/jsr305.jar") + +def _test_location_expansion_with_multiple_artifacts_fails(name): + util.helper_target( + native.filegroup, + name = name + "/fg", + srcs = ["one", "two"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + tools = [name + "/fg"], + javabuilder_jvm_opts = ["$(location " + name + "/fg)"], + ) + + analysis_test( + name = name, + impl = _test_location_expansion_with_multiple_artifacts_fails_impl, + target = name + "/toolchain_java", # the underlying java_toolchain + expect_failure = True, + ) + +def _test_location_expansion_with_multiple_artifacts_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("$(location) expression expands to more than one file"), + ) + +def _test_timezone_data_with_multiple_artifacts_fails(name): + util.helper_target( + native.filegroup, + name = name + "/fg", + srcs = ["one", "two"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + timezone_data = name + "/fg", + ) + + analysis_test( + name = name, + impl = _test_timezone_data_with_multiple_artifacts_fails_impl, + target = name + "/toolchain_java", # the underlying java_toolchain + expect_failure = True, + ) + +def _test_timezone_data_with_multiple_artifacts_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.contains("must produce a single file"), + ) + +def _test_java_compile_action_target_gets_javacopts_from_toolchain(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + source_version = "6", + target_version = "6", + xlint = ["toto"], + javacopts = ["-XDtoolchainJavacFlag"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["a.java"], + ) + analysis_test( + name = name, + impl = _test_java_compile_action_target_gets_javacopts_from_toolchain_impl, + target = name + "/lib", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:javacopt": ["-XDcommandLineJavacFlag"], + "//command_line_option:host_javacopt": ["-XDhostCommandLineJavacFlag"], + }, + ) + +def _test_java_compile_action_target_gets_javacopts_from_toolchain_impl(env, target): + assert_javacopts = javac_action_subject.of(env, target, "{package}/lib{name}.jar").javacopts() + assert_javacopts.contains_exactly([ + "-source", + "6", + "-target", + "6", + "-Xlint:toto", + "-XDtoolchainJavacFlag", + "-XDcommandLineJavacFlag", + ]) + +def _test_java_compile_action_exec_gets_javacopts_from_toolchain(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + source_version = "6", + target_version = "6", + xlint = ["toto"], + javacopts = ["-XDtoolchainJavacFlag"], + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["a.java"], + ) + util.helper_target( + util.force_exec_config, + name = name + "/exec_lib", + tools = [name + "/lib"], + ) + analysis_test( + name = name, + impl = _test_java_compile_action_exec_gets_javacopts_from_toolchain_impl, + target = name + "/exec_lib", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + "//command_line_option:javacopt": ["-XDcommandLineJavacFlag"], + "//command_line_option:host_javacopt": ["-XDhostCommandLineJavacFlag"], + }, + ) + +def _test_java_compile_action_exec_gets_javacopts_from_toolchain_impl(env, target): + lib = env.expect.that_target(target).attr("tools", factory = subjects.collection).actual[0] + assert_javacopts = javac_action_subject.of(env, lib, "{package}/lib{name}.jar").javacopts() + assert_javacopts.contains_exactly([ + "-source", + "6", + "-target", + "6", + "-Xlint:toto", + "-XDtoolchainJavacFlag", + "-XDhostCommandLineJavacFlag", + ]) + +def _test_java_compile_action_uses_tool_specific_jvm_opts(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + jvm_opts = ["-Xbase"], + javabuilder_jvm_opts = ["-DjavabuilderFlag=1"], + turbine_jvm_opts = ["-DturbineFlag=1"], + ) + util.helper_target( + java_plugin, + name = name + "/plugin", + processor_class = "Proc", + generates_api = True, + ) + util.helper_target( + java_library, + name = name + "/lib", + srcs = ["a.java"], + plugins = [name + "/plugin"], + ) + analysis_test( + name = name, + impl = _test_java_compile_action_uses_tool_specific_jvm_opts_impl, + target = name + "/lib", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_java_compile_action_uses_tool_specific_jvm_opts_impl(env, target): + javac_action = javac_action_subject.of(env, target, "{package}/lib{name}.jar") + javac_action.argv().contains("-DjavabuilderFlag=1") + + header_action = env.expect.that_target(target).action_generating("{package}/lib{name}-hjar.jar") + header_action.argv().contains("-DturbineFlag=1") + +def _test_javabuilder_location_expansion_with_multiple_artifacts(name): + util.helper_target( + native.filegroup, + name = name + "/fg1", + srcs = ["a", "b"], + ) + util.helper_target( + native.filegroup, + name = name + "/fg2", + srcs = ["c", "d"], + ) + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + javabuilder_data = [name + "/fg1", name + "/fg2"], + javabuilder_jvm_opts = [ + "$(locations " + name + "/fg1)", + "$(locations " + name + "/fg2)", + ], + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_javabuilder_location_expansion_with_multiple_artifacts_impl, + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_javabuilder_location_expansion_with_multiple_artifacts_impl(env, target): + assert_javabuilder = java_toolchain_info_subject.from_target(env, target).javabuilder() + assert_javabuilder.data().contains_exactly([ + "{package}/a", + "{package}/b", + "{package}/c", + "{package}/d", + ]).in_order() + assert_javabuilder.jvm_opts().contains_exactly([ + "{package}/a {package}/b", + "{package}/c {package}/d", + ]).in_order() + +def _no_toolchain_rule_impl(ctx): + java_common.pack_sources( + ctx.actions, + output_source_jar = "output_source_jar", + java_toolchain = "java_toolchain", + ) + +_no_toolchain_rule = rule( + implementation = _no_toolchain_rule_impl, +) + +def _test_java_common_without_toolchain_type_fails(name): + util.helper_target( + _no_toolchain_rule, + name = name + "/no_toolchain", + ) + analysis_test( + name = name, + impl = _test_java_common_without_toolchain_type_fails_impl, + target = name + "/no_toolchain", + expect_failure = True, + ) + +def _test_java_common_without_toolchain_type_fails_impl(env, target): + env.expect.that_target(target).failures().contains_predicate( + matching.str_matches("must declare *tools/jdk:toolchain_type' toolchain in order to use java_common"), + ) + +def _test_java_toolchain_flag_default(name): + util.helper_target( + java_toolchain_alias, + name = name + "/toolchain_alias", + ) + + analysis_test( + name = name, + impl = _test_java_toolchain_flag_default_impl, + target = name + "/toolchain_alias", + ) + +def _test_java_toolchain_flag_default_impl(env, target): + assert_toolchain = java_toolchain_info_subject.from_target(env, target) + assert_toolchain.label_str().matches( + matching.any( + matching.str_endswith("jdk:remote_toolchain"), + matching.str_endswith("jdk:toolchain"), + matching.str_endswith("jdk:toolchain_host"), + # buildifier: disable=canonical-repository + matching.str_startswith("@@//toolchains:toolchain_java"), + ), + ) + +def _test_java_toolchain_flag_set(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + ) + util.helper_target( + java_toolchain_alias, + name = name + "/toolchain_alias", + ) + + analysis_test( + name = name, + impl = _test_java_toolchain_flag_set_impl, + targets = { + "alias": name + "/toolchain_alias", + "toolchain": name + "/toolchain_java", # the underlying java_toolchain + }, + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_java_toolchain_flag_set_impl(env, targets): + assert_toolchain = java_toolchain_info_subject.from_target(env, targets.alias) + assert_toolchain.label().equals(targets.toolchain.label) + +def _test_default_javac_opts_depset(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + source_version = "6", + target_version = "6", + xlint = ["toto"], + javacopts = ["-Xmaxerrs 500"], + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_default_javac_opts_depset_impl, + target = name + "/alias", + attr_values = {"tags": ["min_bazel_8"]}, + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + ) + +def _test_default_javac_opts_depset_impl(env, target): + java_toolchain_info_subject.from_target(env, target).default_javacopts_depset().contains_exactly( + ["-source 6 -target 6 -Xlint:toto -Xmaxerrs 500"], + ) + +def _test_default_javac_opts(name): + util.helper_target( + mock_java_toolchain, + name = name + "/toolchain", + source_version = "6", + target_version = "6", + ) + util.helper_target( + java_toolchain_alias, + name = name + "/alias", + ) + + analysis_test( + name = name, + impl = _test_default_javac_opts_impl, + target = name + "/alias", + config_settings = { + "//command_line_option:extra_toolchains": [Label(name + "/toolchain")], + }, + attr_values = {"tags": ["min_bazel_8"]}, + ) + +def _test_default_javac_opts_impl(env, target): + java_toolchain_info_subject.from_target(env, target).default_javacopts().contains_at_least([ + "-source", + "6", + "-target", + "6", + ]).in_order() + def java_toolchain_tests(name): test_suite( name = name, tests = [ _test_jacocorunner, + _test_javac_gets_options, + _test_singlejar_get_command_line, + _test_genclass_get_command_line, + _test_timezone_data_is_correct, + _test_java_binary_uses_timezone_data, + _test_ijar_get_command_line, + _test_no_header_compiler_header_compilation_enabled_fails, + _test_no_header_compiler_direct_header_compilation_enabled_fails, + _test_no_header_compiler_header_compilation_disabled_analyzes_successfully, + _test_header_compiler_builtin_processors, + _test_reduced_classpath_incompatible_processors, + _test_location_expansion_in_jvm_opts, + _test_location_expansion_with_multiple_artifacts_fails, + _test_timezone_data_with_multiple_artifacts_fails, + _test_java_compile_action_target_gets_javacopts_from_toolchain, + _test_java_compile_action_exec_gets_javacopts_from_toolchain, + _test_java_compile_action_uses_tool_specific_jvm_opts, + _test_javabuilder_location_expansion_with_multiple_artifacts, + _test_java_common_without_toolchain_type_fails, + _test_java_toolchain_flag_default, + _test_java_toolchain_flag_set, + _test_default_javac_opts_depset, + _test_default_javac_opts, ], ) diff --git a/test/repo/BUILD.bazel b/test/repo/BUILD.bazel index ca414395..a251c7b7 100644 --- a/test/repo/BUILD.bazel +++ b/test/repo/BUILD.bazel @@ -1,4 +1,5 @@ load("@rules_java//java:defs.bzl", "java_binary", "java_library", "java_test") # copybara-use-repo-external-label +load("@rules_java//java:java_single_jar.bzl", "java_single_jar") # copybara-use-repo-external-label load("@rules_java//toolchains:default_java_toolchain.bzl", "NONPREBUILT_TOOLCHAIN_CONFIGURATION", "default_java_toolchain") # copybara-use-repo-external-label load("@rules_shell//shell:sh_test.bzl", "sh_test") @@ -27,6 +28,15 @@ java_test( ], ) +java_single_jar( + name = "uber", + testonly = True, + deps = [ + ":MyTest", + ":bin", + ], +) + genrule( name = "MakeVarGenruleTest", outs = ["MakeVarGenruleTestSuccess"], @@ -53,4 +63,9 @@ default_java_toolchain( name = "my_funky_toolchain", bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath"], configuration = NONPREBUILT_TOOLCHAIN_CONFIGURATION, + exec_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + java_runtime = "@my_funky_jdk//:jdk", ) diff --git a/test/repo/MODULE.bazel b/test/repo/MODULE.bazel index 1faec90d..5f300800 100644 --- a/test/repo/MODULE.bazel +++ b/test/repo/MODULE.bazel @@ -27,6 +27,7 @@ use_repo( "remote_java_tools_darwin_arm64", "remote_java_tools_darwin_x86_64", "remote_java_tools_linux", + "remote_java_tools_linux_aarch64", "remote_java_tools_windows", "remotejdk11_linux", "remotejdk11_linux_aarch64", @@ -49,6 +50,25 @@ use_repo( "remotejdk21_win", ) +custom_jdk = use_extension("@rules_java//java:extensions.bzl", "java_repository") +custom_jdk.remote( + name = "my_funky_jdk", + prefix = "funky", + strip_prefix = "zulu24.32.13-ca-jdk24.0.2-linux_x64", + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + urls = [ + "https://cdn.azul.com/zulu/bin/zulu24.32.13-ca-jdk24.0.2-linux_x64.tar.gz", + ], + version = "24", +) +use_repo(custom_jdk, "my_funky_jdk", "my_funky_jdk_toolchain_config_repo") + +register_toolchains("@my_funky_jdk_toolchain_config_repo//:all") + register_toolchains("//:all") bazel_dep(name = "rules_shell", version = "0.4.0", dev_dependency = True) +bazel_dep(name = "platforms", version = "0.0.11", dev_dependency = True) diff --git a/test/repo/WORKSPACE b/test/repo/WORKSPACE index c272975e..32cadb59 100644 --- a/test/repo/WORKSPACE +++ b/test/repo/WORKSPACE @@ -5,14 +5,23 @@ local_repository( path = "../../", ) -load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") -rules_java_dependencies() +http_archive( + name = "bazel_features", + sha256 = "a660027f5a87f13224ab54b8dc6e191693c554f2692fcca46e8e29ee7dabc43b", + strip_prefix = "bazel_features-1.30.0", + url = "https://github.com/bazel-contrib/bazel_features/releases/download/v1.30.0/bazel_features-v1.30.0.tar.gz", +) load("@bazel_features//:deps.bzl", "bazel_features_deps") bazel_features_deps() +load("@rules_java//java:rules_java_deps.bzl", "rules_java_dependencies") + +rules_java_dependencies() + load("@com_google_protobuf//bazel/private:proto_bazel_features.bzl", "proto_bazel_features") # buildifier: disable=bzl-visibility proto_bazel_features(name = "proto_bazel_features") @@ -33,8 +42,6 @@ http_jar( ], ) -load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") - http_archive( name = "rules_shell", sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043", @@ -47,3 +54,21 @@ load("@rules_shell//shell:repositories.bzl", "rules_shell_dependencies", "rules_ rules_shell_dependencies() rules_shell_toolchains() + +load("@rules_java//toolchains:remote_java_repository.bzl", "remote_java_repository") + +remote_java_repository( + name = "my_funky_jdk", + prefix = "funky", + strip_prefix = "zulu24.32.13-ca-jdk24.0.2-linux_x64", + target_compatible_with = [ + "@platforms//os:linux", + "@platforms//cpu:x86_64", + ], + urls = [ + "https://cdn.azul.com/zulu/bin/zulu24.32.13-ca-jdk24.0.2-linux_x64.tar.gz", + ], + version = "24", +) + +register_toolchains("@my_funky_jdk_toolchain_config_repo//:all") diff --git a/test/repositories.bzl b/test/repositories.bzl index 5d4f568d..0f0afd53 100644 --- a/test/repositories.bzl +++ b/test/repositories.bzl @@ -5,6 +5,7 @@ load("@bazel_skylib//lib:modules.bzl", "modules") # TODO: Use http_jar from //java:http_jar.bzl once it doesn't refert to cache.bzl from @bazel_tools # anymore, which isn't available in Bazel 6. load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file") +load("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository") def test_repositories(): http_file( @@ -19,5 +20,9 @@ def test_repositories(): integrity = "sha256-Ushs3a3DG8hFfB4VaJ/Gt14ul84qg9i1S3ldVW1In4w=", downloaded_file_path = "truth.jar", ) + local_repository( + name = "other_repo", + path = "test/testdata/other_repo", + ) test_repositories_ext = modules.as_extension(test_repositories) diff --git a/test/testdata/other_repo/BUILD.bazel b/test/testdata/other_repo/BUILD.bazel new file mode 100644 index 00000000..fc25d5fb --- /dev/null +++ b/test/testdata/other_repo/BUILD.bazel @@ -0,0 +1 @@ +exports_files(["ExternalLib.java"]) diff --git a/test/testdata/other_repo/MODULE.bazel b/test/testdata/other_repo/MODULE.bazel new file mode 100644 index 00000000..f90d195a --- /dev/null +++ b/test/testdata/other_repo/MODULE.bazel @@ -0,0 +1 @@ +module(name = "other_repo") diff --git a/test/toolchains/bootclasspath_tests.bzl b/test/toolchains/bootclasspath_tests.bzl index 5eb436a0..15ccd4ff 100644 --- a/test/toolchains/bootclasspath_tests.bzl +++ b/test/toolchains/bootclasspath_tests.bzl @@ -13,6 +13,9 @@ def _test_utf_8_environment(name): def _test_utf_8_environment_impl(env, target): for action in target.actions: + if action.mnemonic == "Ijar": + # ijar isn't sensitive to locales + continue env_subject = env.expect.where(action = action).that_dict(action.env) env_subject.keys().contains("LC_CTYPE") env_subject.get("LC_CTYPE", factory = subjects.str).contains("UTF-8") @@ -65,6 +68,53 @@ def _test_incompatible_language_version_bootclasspath_enabled_unversioned_impl(e system_path = target[java_common.BootClassPathInfo]._system_path env.expect.that_str(system_path).contains("local_jdk") +def _test_jdk8_uses_tree_artifact(name): + analysis_test( + name = name, + impl = _test_jdk8_uses_tree_artifact_impl, + target = Label("//toolchains:platformclasspath"), + config_settings = { + "//command_line_option:tool_java_runtime_version": "remotejdk_8", + }, + ) + +def _test_jdk8_uses_tree_artifact_impl(env, target): + env.expect.that_target(target).action_named( + "JavaToolchainCompileClasses", + ).argv().contains_at_least([ + "-d", + "{bindir}/{package}/{name}_classes", + "toolchains/DumpPlatformClassPath.java", + ]).in_order() + env.expect.that_target(target).action_named( + "JavaToolchainCompileBootClasspath", + ).argv().contains_at_least([ + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "-cp", + "{bindir}/{package}/{name}_classes", + "DumpPlatformClassPath", + "{bindir}/{package}/{name}_unstripped.jar", + ]).in_order() + +def _test_jdk11_uses_source_launcher(name): + analysis_test( + name = name, + impl = _test_jdk11_uses_source_launcher_impl, + target = Label("//toolchains:platformclasspath"), + config_settings = { + "//command_line_option:tool_java_runtime_version": "remotejdk_11", + }, + ) + +def _test_jdk11_uses_source_launcher_impl(env, target): + env.expect.that_target(target).action_named( + "JavaToolchainCompileBootClasspath", + ).argv().contains_at_least([ + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "toolchains/DumpPlatformClassPath.java", + "{bindir}/{package}/{name}_unstripped.jar", + ]).in_order() + def bootclasspath_tests(name): test_suite( name = name, @@ -73,5 +123,7 @@ def bootclasspath_tests(name): _test_incompatible_language_version_bootclasspath_disabled, _test_incompatible_language_version_bootclasspath_enabled_versioned, _test_incompatible_language_version_bootclasspath_enabled_unversioned, + _test_jdk8_uses_tree_artifact, + _test_jdk11_uses_source_launcher, ], ) diff --git a/third_party/BUILD b/third_party/BUILD new file mode 100644 index 00000000..e69de29b diff --git a/third_party/protobuf_load-cc-rules.patch b/third_party/protobuf_load-cc-rules.patch new file mode 100644 index 00000000..09bd7025 --- /dev/null +++ b/third_party/protobuf_load-cc-rules.patch @@ -0,0 +1,157 @@ +Backported from https://github.com/protocolbuffers/protobuf/pull/23584 to 32.0: + +From 733a0ccf6f53f469352b19440a1d152eccea6bec Mon Sep 17 00:00:00 2001 +From: Keith Smiley +Date: Sat, 20 Sep 2025 09:30:37 -0700 +Subject: [PATCH] bazel: add missing rules_cc loads + +This is required for use with bazel after this commit https://github.com/bazelbuild/bazel/commit/71ca0ed111ff3d842a0d23bc3a46bd2e6745491d + +Many files have these already +--- + lua/BUILD.bazel | 3 +++ + pkg/test/BUILD.bazel | 1 + + ruby/ext/google/protobuf_c/BUILD.bazel | 1 + + ruby/lib/google/BUILD.bazel | 1 + + rust/defs.bzl | 1 + + src/google/protobuf/compiler/cpp/BUILD.bazel | 1 + + src/google/protobuf/compiler/java/full/BUILD.bazel | 1 + + src/google/protobuf/compiler/java/lite/BUILD.bazel | 1 + + src/google/protobuf/compiler/kotlin/BUILD.bazel | 1 + + src/google/protobuf/compiler/php/BUILD.bazel | 1 + + src/google/protobuf/compiler/rust/BUILD.bazel | 2 ++ + toolchain/BUILD.bazel | 2 ++ + 12 files changed, 16 insertions(+) + +diff --git a/lua/BUILD.bazel b/lua/BUILD.bazel +index 389e5da7635ca..db956713bd849 100644 +--- a/lua/BUILD.bazel ++++ b/lua/BUILD.bazel +@@ -5,6 +5,9 @@ + # license that can be found in the LICENSE file or at + # https://developers.google.com/open-source/licenses/bsd + ++load("@rules_cc//cc:cc_binary.bzl", "cc_binary") ++load("@rules_cc//cc:cc_library.bzl", "cc_library") ++load("@rules_cc//cc:cc_test.bzl", "cc_test") + load("//bazel:proto_library.bzl", "proto_library") + load( + "//lua:lua_proto_library.bzl", +diff --git a/pkg/test/BUILD.bazel b/pkg/test/BUILD.bazel +index d0954f0126ba2..4fd01c9759643 100644 +--- a/pkg/test/BUILD.bazel ++++ b/pkg/test/BUILD.bazel +@@ -1,5 +1,6 @@ + # Tests for CMake file list generation + ++load("@rules_cc//cc:cc_library.bzl", "cc_library") + load("@rules_shell//shell:sh_test.bzl", "sh_test") + load("//pkg:build_systems.bzl", "gen_file_lists") + load("//pkg:cc_dist_library.bzl", "cc_dist_library") +diff --git a/ruby/ext/google/protobuf_c/BUILD.bazel b/ruby/ext/google/protobuf_c/BUILD.bazel +index 00458e2eedbe4..63276d538cc5c 100644 +--- a/ruby/ext/google/protobuf_c/BUILD.bazel ++++ b/ruby/ext/google/protobuf_c/BUILD.bazel +@@ -1,4 +1,5 @@ + load("@build_bazel_rules_apple//apple:apple_binary.bzl", "apple_binary") ++load("@rules_cc//cc:cc_library.bzl", "cc_library") + load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") + load("//upb/cmake:build_defs.bzl", "staleness_test") + +diff --git a/ruby/lib/google/BUILD.bazel b/ruby/lib/google/BUILD.bazel +index db0d7cd6b89bc..157df81b6d734 100644 +--- a/ruby/lib/google/BUILD.bazel ++++ b/ruby/lib/google/BUILD.bazel +@@ -1,3 +1,4 @@ ++load("@rules_cc//cc:cc_binary.bzl", "cc_binary") + load("@rules_java//java:java_binary.bzl", "java_binary") + load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") + load("@rules_ruby//ruby:defs.bzl", "rb_library") +diff --git a/rust/defs.bzl b/rust/defs.bzl +index b787d108fc743..54dab26e25048 100644 +--- a/rust/defs.bzl ++++ b/rust/defs.bzl +@@ -1,4 +1,5 @@ + """This file implements rust_proto_library.""" + ++load("@rules_cc//cc/common:cc_info.bzl", "CcInfo") + load("@rules_rust//rust:defs.bzl", "rust_common") + load("//bazel/common:proto_common.bzl", "proto_common") +diff --git a/src/google/protobuf/compiler/cpp/BUILD.bazel b/src/google/protobuf/compiler/cpp/BUILD.bazel +index 4d4e99d774772..ced92c04e235d 100644 +--- a/src/google/protobuf/compiler/cpp/BUILD.bazel ++++ b/src/google/protobuf/compiler/cpp/BUILD.bazel +@@ -2,6 +2,7 @@ + # Protocol Buffers Compiler - C++ code generator + ################################################################################ + ++load("@rules_cc//cc:cc_binary.bzl", "cc_binary") + load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test") + load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") + load("//bazel:cc_proto_library.bzl", "cc_proto_library") +diff --git a/src/google/protobuf/compiler/java/full/BUILD.bazel b/src/google/protobuf/compiler/java/full/BUILD.bazel +index 6bffaa10fbc87..54b4ae9cd186d 100644 +--- a/src/google/protobuf/compiler/java/full/BUILD.bazel ++++ b/src/google/protobuf/compiler/java/full/BUILD.bazel +@@ -1,6 +1,7 @@ + # We use abbreviated target names in this directory to work around: + # https://github.com/bazelbuild/bazel/issues/18683 + ++load("@rules_cc//cc:cc_library.bzl", "cc_library") + load("//build_defs:cpp_opts.bzl", "COPTS") + + cc_library( +diff --git a/src/google/protobuf/compiler/java/lite/BUILD.bazel b/src/google/protobuf/compiler/java/lite/BUILD.bazel +index 02af1b3f917df..5e04135abbac0 100644 +--- a/src/google/protobuf/compiler/java/lite/BUILD.bazel ++++ b/src/google/protobuf/compiler/java/lite/BUILD.bazel +@@ -1,3 +1,4 @@ ++load("@rules_cc//cc:cc_library.bzl", "cc_library") + load("//build_defs:cpp_opts.bzl", "COPTS") + + cc_library( +diff --git a/src/google/protobuf/compiler/kotlin/BUILD.bazel b/src/google/protobuf/compiler/kotlin/BUILD.bazel +index 4f866ae02e1b7..5a1e1b727092b 100644 +--- a/src/google/protobuf/compiler/kotlin/BUILD.bazel ++++ b/src/google/protobuf/compiler/kotlin/BUILD.bazel +@@ -1,3 +1,4 @@ ++load("@rules_cc//cc:cc_library.bzl", "cc_library") + load("//build_defs:cpp_opts.bzl", "COPTS") + + cc_library( +diff --git a/src/google/protobuf/compiler/php/BUILD.bazel b/src/google/protobuf/compiler/php/BUILD.bazel +index 930db4476125b..d41fe6d122adb 100644 +--- a/src/google/protobuf/compiler/php/BUILD.bazel ++++ b/src/google/protobuf/compiler/php/BUILD.bazel +@@ -2,6 +2,7 @@ + # Protocol Buffers Compiler - PHP code generator + ################################################################################ + ++load("@rules_cc//cc:cc_test.bzl", "cc_test") + load("@rules_cc//cc:defs.bzl", "cc_library") + load("@rules_pkg//pkg:mappings.bzl", "pkg_files", "strip_prefix") + load("//build_defs:cpp_opts.bzl", "COPTS") +diff --git a/src/google/protobuf/compiler/rust/BUILD.bazel b/src/google/protobuf/compiler/rust/BUILD.bazel +index e5766c2abd40b..116e44b76df9c 100644 +--- a/src/google/protobuf/compiler/rust/BUILD.bazel ++++ b/src/google/protobuf/compiler/rust/BUILD.bazel +@@ -9,6 +9,8 @@ + # Protocol Buffers Compiler - Rust code generator + ################################################################################ + ++load("@rules_cc//cc:cc_binary.bzl", "cc_binary") ++load("@rules_cc//cc:cc_test.bzl", "cc_test") + load("@rules_cc//cc:defs.bzl", "cc_library") + load("//build_defs:cpp_opts.bzl", "COPTS") + load( +diff --git a/toolchain/BUILD.bazel b/toolchain/BUILD.bazel +index 524fa14390501..4cb056c75ff66 100644 +--- a/toolchain/BUILD.bazel ++++ b/toolchain/BUILD.bazel +@@ -1,4 +1,6 @@ + load("@bazel_skylib//rules:common_settings.bzl", "bool_flag") ++load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain") ++load("@rules_cc//cc/toolchains:cc_toolchain_suite.bzl", "cc_toolchain_suite") + load(":cc_toolchain_config.bzl", "cc_toolchain_config") + + package(default_visibility = ["//visibility:public"]) diff --git a/toolchains/BUILD b/toolchains/BUILD index 9a1b2d33..0f3ef2bf 100644 --- a/toolchains/BUILD +++ b/toolchains/BUILD @@ -190,6 +190,7 @@ cc_library( ) for OS in [ "linux", + "linux_aarch64", "darwin_x86_64", "darwin_arm64", "windows", @@ -207,6 +208,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":ijar_prebuilt_binary_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":ijar_prebuilt_binary_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":ijar_prebuilt_binary_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":ijar_prebuilt_binary_linux_aarch64", "@bazel_tools//src/conditions:windows": ":ijar_prebuilt_binary_windows", "//conditions:default": "@remote_java_tools//:ijar_cc_binary", }), @@ -218,6 +220,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":ijar_prebuilt_binary_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":ijar_prebuilt_binary_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":ijar_prebuilt_binary_linux", + "@bazel_tools//src/conditions:linux_aarch64": "ijar_prebuilt_binary_linux_aarch64", "@bazel_tools//src/conditions:windows": ":ijar_prebuilt_binary_windows", }), ) @@ -233,6 +236,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":prebuilt_singlejar_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":prebuilt_singlejar_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":prebuilt_singlejar_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":prebuilt_singlejar_linux_aarch64", "@bazel_tools//src/conditions:windows": ":prebuilt_singlejar_windows", "//conditions:default": "@remote_java_tools//:singlejar_cc_bin", }), @@ -244,6 +248,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":prebuilt_singlejar_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":prebuilt_singlejar_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":prebuilt_singlejar_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":prebuilt_singlejar_linux_aarch64", "@bazel_tools//src/conditions:windows": ":prebuilt_singlejar_windows", }), ) @@ -259,6 +264,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":prebuilt_one_version_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":prebuilt_one_version_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":prebuilt_one_version_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":prebuilt_one_version_linux_aarch64", "@bazel_tools//src/conditions:windows": ":prebuilt_one_version_windows", "//conditions:default": "@remote_java_tools//:one_version_cc_bin", }), @@ -270,6 +276,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":prebuilt_one_version_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":prebuilt_one_version_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":prebuilt_one_version_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":prebuilt_one_version_linux_aarch64", "@bazel_tools//src/conditions:windows": ":prebuilt_one_version_windows", }), ) @@ -285,6 +292,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":turbine_direct_graal_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":turbine_direct_graal_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":turbine_direct_graal_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":turbine_direct_graal_linux_aarch64", "@bazel_tools//src/conditions:windows": ":turbine_direct_graal_windows", "//conditions:default": "@remote_java_tools//:TurbineDirect", }), @@ -296,6 +304,7 @@ alias( "@bazel_tools//src/conditions:darwin_arm64": ":turbine_direct_graal_darwin_arm64", "@bazel_tools//src/conditions:darwin_x86_64": ":turbine_direct_graal_darwin_x86_64", "@bazel_tools//src/conditions:linux_x86_64": ":turbine_direct_graal_linux", + "@bazel_tools//src/conditions:linux_aarch64": ":turbine_direct_graal_linux_aarch64", "@bazel_tools//src/conditions:windows": ":turbine_direct_graal_windows", }), ) @@ -342,6 +351,17 @@ bootclasspath( }), ) +bootclasspath( + name = "platformclasspath_nostrip", + src = "DumpPlatformClassPath.java", + java_runtime_alias = ":current_java_runtime", + language_version_bootstrap_runtime = select({ + ":incompatible_language_version_bootclasspath_enabled": ":language_version_bootstrap_runtime", + "//conditions:default": None, + }), + strip = False, +) + default_java_toolchain( name = "toolchain", configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, @@ -353,12 +373,12 @@ alias( actual = ":toolchain", ) -RELEASES = (8, 9, 10, 11, 17, 21) +RELEASES = (8, 9, 10, 11, 17, 21, 25) [ default_java_toolchain( name = ("toolchain_java%d" if release <= 11 else "toolchain_jdk_%d") % release, - configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, + configuration = DEFAULT_TOOLCHAIN_CONFIGURATION | {"java_runtime": ":remotejdk_25"}, source_version = "%s" % release, target_version = "%s" % release, ) @@ -390,6 +410,12 @@ java_runtime_version_alias( visibility = ["//visibility:public"], ) +java_runtime_version_alias( + name = "remotejdk_25", + runtime_version = "remotejdk_25", + visibility = ["//visibility:public"], +) + java_runtime_version_alias( name = "jdk_8", runtime_version = "8", diff --git a/toolchains/bootclasspath.bzl b/toolchains/bootclasspath.bzl index d89aa171..256c032f 100644 --- a/toolchains/bootclasspath.bzl +++ b/toolchains/bootclasspath.bzl @@ -101,6 +101,21 @@ _bootclasspath_transition = transition( ], ) +def _run_ijar(*, actions, label, ijar, input, output): + args = actions.args() + args.add(input) + args.add(output) + args.add("--target_label", label) + actions.run( + inputs = [input], + outputs = [output], + executable = ijar, + arguments = [args], + progress_message = "Extracting interfaces from %{input}", + execution_requirements = _SUPPORTS_PATH_MAPPING, + mnemonic = "Ijar", + ) + _JAVA_BOOTSTRAP_RUNTIME_TOOLCHAIN_TYPE = Label("@bazel_tools//tools/jdk:bootstrap_runtime_toolchain_type") # Opt the Java bootstrap actions into path mapping: @@ -114,31 +129,37 @@ def _bootclasspath_impl(ctx): exec_javabase = ctx.attr.java_runtime_alias[java_common.JavaRuntimeInfo] env = ctx.attr._utf8_environment[Utf8EnvironmentInfo].environment - class_dir = ctx.actions.declare_directory("%s_classes" % ctx.label.name) + # If possible, use JDK 11+'s ability to run a single Java file to avoid a + # separate action to compile DumpPlatformClassPath. + use_source_launcher = exec_javabase.version >= 11 - args = ctx.actions.args() - args.add("-source") - args.add("8") - args.add("-target") - args.add("8") - args.add("-Xlint:-options") - args.add("-J-XX:-UsePerfData") - args.add("-d") - args.add_all([class_dir], expand_directories = False) - args.add(ctx.file.src) + class_dir = None + if not use_source_launcher: + class_dir = ctx.actions.declare_directory("%s_classes" % ctx.label.name) - ctx.actions.run( - executable = "%s/bin/javac" % exec_javabase.java_home, - mnemonic = "JavaToolchainCompileClasses", - inputs = [ctx.file.src] + ctx.files.java_runtime_alias, - outputs = [class_dir], - arguments = [args], - env = env, - execution_requirements = _SUPPORTS_PATH_MAPPING, - use_default_shell_env = True, - ) + args = ctx.actions.args() + args.add("-source") + args.add("8") + args.add("-target") + args.add("8") + args.add("-Xlint:-options") + args.add("-J-XX:-UsePerfData") + args.add("-d") + args.add_all([class_dir], expand_directories = False) + args.add(ctx.file.src) - bootclasspath = ctx.outputs.output_jar + ctx.actions.run( + executable = "%s/bin/javac" % exec_javabase.java_home, + mnemonic = "JavaToolchainCompileClasses", + inputs = [ctx.file.src] + ctx.files.java_runtime_alias, + outputs = [class_dir], + arguments = [args], + env = env, + execution_requirements = _SUPPORTS_PATH_MAPPING, + use_default_shell_env = True, + ) + + unstripped_bootclasspath = ctx.actions.declare_file("%s_unstripped.jar" % ctx.label.name) args = ctx.actions.args() args.add("-XX:+IgnoreUnrecognizedVMOptions") @@ -146,9 +167,14 @@ def _bootclasspath_impl(ctx): args.add("--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED") args.add("--add-exports=jdk.compiler/com.sun.tools.javac.platform=ALL-UNNAMED") args.add("--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED") - args.add_all("-cp", [class_dir], expand_directories = False) - args.add("DumpPlatformClassPath") - args.add(bootclasspath) + + if use_source_launcher: + args.add(ctx.file.src) + else: + args.add_all("-cp", [class_dir], expand_directories = False) + args.add("DumpPlatformClassPath") + + args.add(unstripped_bootclasspath) if ctx.attr.language_version_bootstrap_runtime: # The attribute is subject to a split transition. @@ -196,17 +222,30 @@ Rerun with --toolchain_resolution_debug='@bazel_tools//tools/jdk:bootstrap_runti if len(system) != len(system_files): system = None - inputs = depset([class_dir] + ctx.files.java_runtime_alias, transitive = [any_javabase.files]) + classpath_input = ctx.file.src if use_source_launcher else class_dir + inputs = depset([classpath_input] + ctx.files.java_runtime_alias, transitive = [any_javabase.files]) ctx.actions.run( executable = str(exec_javabase.java_executable_exec_path), mnemonic = "JavaToolchainCompileBootClasspath", inputs = inputs, - outputs = [bootclasspath], + outputs = [unstripped_bootclasspath], arguments = [args], env = env, execution_requirements = _SUPPORTS_PATH_MAPPING, use_default_shell_env = True, ) + + bootclasspath = ctx.outputs.output_jar + if ctx.attr.strip: + _run_ijar( + actions = ctx.actions, + label = ctx.label, + ijar = ctx.executable._ijar, + input = unstripped_bootclasspath, + output = bootclasspath, + ) + else: + ctx.actions.symlink(output = bootclasspath, target_file = unstripped_bootclasspath) return [ DefaultInfo(files = depset([bootclasspath])), java_common.BootClassPathInfo( @@ -216,6 +255,9 @@ Rerun with --toolchain_resolution_debug='@bazel_tools//tools/jdk:bootstrap_runti OutputGroupInfo(jar = [bootclasspath]), ] +def _compute_ijar(strip): + return Label("//toolchains:ijar") if strip else None + _bootclasspath = rule( implementation = _bootclasspath_impl, attrs = { @@ -231,9 +273,15 @@ _bootclasspath = rule( cfg = "exec", allow_single_file = True, ), + "strip": attr.bool(default = True), "_allowlist_function_transition": attr.label( default = "@bazel_tools//tools/allowlists/function_transition_allowlist", ), + "_ijar": attr.label( + default = _compute_ijar, + cfg = "exec", + executable = True, + ), "_utf8_environment": attr.label( default = ":utf8_environment", cfg = "exec", diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl index 4ec8961a..f4f83f66 100644 --- a/toolchains/default_java_toolchain.bzl +++ b/toolchains/default_java_toolchain.bzl @@ -59,14 +59,15 @@ DEFAULT_JAVACOPTS = [ "--should-stop=ifError=FLOW", # See b/27049950, https://github.com/google/error-prone/issues/4595 "-g", "-parameters", - # https://github.com/bazelbuild/bazel/issues/15219 - "-Xep:ReturnValueIgnored:OFF", # https://github.com/bazelbuild/bazel/issues/16996 "-Xep:IgnoredPureGetter:OFF", "-Xep:EmptyTopLevelDeclaration:OFF", "-Xep:LenientFormatStringValidation:OFF", "-Xep:ReturnMissingNullable:OFF", "-Xep:UseCorrectAssertInTests:OFF", + # Please see https://github.com/bazelbuild/bazel/issues/25927#issuecomment-2825206105 + # we need to make sure not to filter any warnings so that Bazel can trigger them as errors. + "-Xmaxwarns -1", ] # If this is changed, the docs for "{,tool_}java_language_version" also @@ -76,11 +77,11 @@ _DEFAULT_JAVA_LANGUAGE_VERSION = "11" # Default java_toolchain parameters _BASE_TOOLCHAIN_CONFIGURATION = dict( forcibly_disable_header_compilation = False, - genclass = [Label("@remote_java_tools//:GenClass")], - header_compiler = [Label("@remote_java_tools//:TurbineDirect")], - header_compiler_direct = [Label("//toolchains:turbine_direct")], - ijar = [Label("//toolchains:ijar")], - javabuilder = [Label("@remote_java_tools//:JavaBuilder")], + genclass = Label("@remote_java_tools//:GenClass"), + header_compiler = Label("@remote_java_tools//:TurbineDirect"), + header_compiler_direct = Label("//toolchains:turbine_direct"), + ijar = Label("//toolchains:ijar"), + javabuilder = Label("@remote_java_tools//:JavaBuilder"), javac_supports_workers = True, jacocorunner = Label("@remote_java_tools//:jacoco_coverage_runner_filegroup"), jvm_opts = BASE_JDK9_JVM_OPTS, @@ -89,7 +90,7 @@ _BASE_TOOLCHAIN_CONFIGURATION = dict( "-XX:+UseParallelGC", ], misc = DEFAULT_JAVACOPTS, - singlejar = [Label("//toolchains:singlejar")], + singlejar = Label("//toolchains:singlejar"), # Code to enumerate target JVM boot classpath uses host JVM. Because # java_runtime-s are involved, its implementation is in @bazel_tools. bootclasspath = [Label("//toolchains:platformclasspath")], @@ -98,6 +99,8 @@ _BASE_TOOLCHAIN_CONFIGURATION = dict( reduced_classpath_incompatible_processors = [ "dagger.hilt.processor.internal.root.RootProcessor", # see b/21307381 ], + # TODO: Update to JDK 25 after some time has passed - it no longer supports + # targeting JDK 7. java_runtime = Label("//toolchains:remotejdk_21"), oneversion = Label("//toolchains:one_version"), ) @@ -118,7 +121,7 @@ DEFAULT_TOOLCHAIN_CONFIGURATION = _BASE_TOOLCHAIN_CONFIGURATION # However it does allow using a wider range of `--host_javabase`s, including # versions newer than the current JDK. VANILLA_TOOLCHAIN_CONFIGURATION = dict( - javabuilder = [Label("@remote_java_tools//:VanillaJavaBuilder")], + javabuilder = Label("@remote_java_tools//:VanillaJavaBuilder"), jvm_opts = [], java_runtime = None, ) @@ -129,17 +132,18 @@ VANILLA_TOOLCHAIN_CONFIGURATION = dict( # same, otherwise the binaries will not work on the execution # platform. PREBUILT_TOOLCHAIN_CONFIGURATION = dict( - ijar = [Label("//toolchains:ijar_prebuilt_binary")], - singlejar = [Label("//toolchains:prebuilt_singlejar")], + ijar = Label("//toolchains:ijar_prebuilt_binary"), + singlejar = Label("//toolchains:prebuilt_singlejar"), oneversion = Label("//toolchains:prebuilt_one_version"), ) # The new toolchain is using all the tools from sources. NONPREBUILT_TOOLCHAIN_CONFIGURATION = dict( - ijar = [Label("@remote_java_tools//:ijar_cc_binary")], - singlejar = [Label("@remote_java_tools//:singlejar_cc_bin")], - header_compiler_direct = [Label("@remote_java_tools//:TurbineDirect")], + ijar = Label("@remote_java_tools//:ijar_cc_binary"), + singlejar = Label("@remote_java_tools//:singlejar_cc_bin"), + header_compiler_direct = Label("@remote_java_tools//:TurbineDirect"), oneversion = Label("@remote_java_tools//:one_version_cc_bin"), + bootclasspath = [Label("//toolchains:platformclasspath_nostrip")], ) def default_java_toolchain(name, configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, toolchain_definition = True, exec_compatible_with = [], target_compatible_with = [], **kwargs): diff --git a/toolchains/extensions.bzl b/toolchains/extensions.bzl new file mode 100644 index 00000000..1db0cbc9 --- /dev/null +++ b/toolchains/extensions.bzl @@ -0,0 +1,63 @@ +"""Module extensions for local and remote java repositories""" + +load(":local_java_repository.bzl", "local_java_repository") +load(":remote_java_repository.bzl", "remote_java_repository") + +visibility(["//java"]) + +def _java_repository_impl(mctx): + for mod in mctx.modules: + if not mod.is_root: + fail( + """This module extension may only be used in the root module. {name} + must set `dev_dependency` = True on it's usage of this extension, + if {name} can be dependency of other modules.""".format(name = mod.name), + ) + for local in mod.tags.local: + local_java_repository( + local.name, + java_home = local.java_home, + version = local.version, + build_file = local.build_file, + build_file_content = local.build_file_content, + ) + for remote in mod.tags.remote: + remote_java_repository( + remote.name, + remote.version, + target_compatible_with = remote.target_compatible_with, + prefix = remote.prefix, + remote_file_urls = remote.remote_file_urls, + remote_file_integrity = remote.remote_file_integrity, + sha256 = remote.sha256, + strip_prefix = remote.strip_prefix, + urls = remote.urls, + ) + +_local = tag_class(attrs = { + "name": attr.string(mandatory = True), + "build_file": attr.label(default = None), + "build_file_content": attr.string(default = ""), + "java_home": attr.string(default = ""), + "version": attr.string(default = ""), +}) + +_remote = tag_class(attrs = { + "name": attr.string(mandatory = True), + "version": attr.string(mandatory = True), + "urls": attr.string_list(mandatory = True), + "prefix": attr.string(default = ""), + "remote_file_urls": attr.string_list_dict(default = {}), + "remote_file_integrity": attr.string_dict(default = {}), + "sha256": attr.string(default = ""), + "strip_prefix": attr.string(default = ""), + "target_compatible_with": attr.string_list(default = []), +}) + +java_repository = module_extension( + _java_repository_impl, + tag_classes = { + "local": _local, + "remote": _remote, + }, +) diff --git a/toolchains/local_java_repository.bzl b/toolchains/local_java_repository.bzl index 075f54d6..769c2d19 100644 --- a/toolchains/local_java_repository.bzl +++ b/toolchains/local_java_repository.bzl @@ -235,18 +235,10 @@ local_java_runtime( ) """ % (local_java_runtime_name, runtime_name, java_home, version) - bazel = native.bazel_version - if not bazel or bazel >= "7": - # Bazel 7+ uses @platforms//host for the host platform. - load_host_constraints = 'load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS")\n' - else: - # Bazel 6 uses @local_config_platform instead, but it's being removed in Bazel 9. - load_host_constraints = 'load("@local_config_platform//:constraints.bzl", "HOST_CONSTRAINTS")\n' - repository_ctx.file( "BUILD.bazel", 'load("@rules_java//toolchains:local_java_repository.bzl", "local_java_runtime")\n' + - load_host_constraints + + 'load("@platforms//host:constraints.bzl", "HOST_CONSTRAINTS")\n' + build_file + local_java_runtime_macro, )