Copy over files from @bazel_tools//tools/jdk
diff --git a/toolchains/BUILD b/toolchains/BUILD index 67d2c89..6f7fef4 100644 --- a/toolchains/BUILD +++ b/toolchains/BUILD
@@ -1,3 +1,21 @@ +load( + "@bazel_tools//tools/jdk:default_java_toolchain.bzl", + "DEFAULT_TOOLCHAIN_CONFIGURATION", + "JVM8_TOOLCHAIN_CONFIGURATION", + "PREBUILT_TOOLCHAIN_CONFIGURATION", + "VANILLA_TOOLCHAIN_CONFIGURATION", + "bootclasspath", + "default_java_toolchain", + "java_runtime_files", +) +load( + "//tools/jdk:java_toolchain_alias.bzl", + "java_host_runtime_alias", + "java_runtime_alias", + "java_runtime_version_alias", + "java_toolchain_alias", +) + package(default_visibility = ["//visibility:public"]) licenses(["notice"]) @@ -7,3 +25,490 @@ srcs = glob(["**"]), visibility = ["@//:__pkg__"], ) + + +load("//tools/python:private/defs.bzl", "py_binary", "py_test") + +package(default_visibility = ["//visibility:public"]) + +# Used to distinguish toolchains used for Java development, ie the JavaToolchainProvider. +toolchain_type(name = "toolchain_type") + +# Used to distinguish toolchains used for Java execution, ie the JavaRuntimeInfo. +toolchain_type(name = "runtime_toolchain_type") + +# Points to toolchain[":runtime_toolchain_type"] (was :legacy_current_java_runtime) +java_runtime_alias(name = "current_java_runtime") + +# Host configuration of ":current_java_runtime" +java_host_runtime_alias(name = "current_host_java_runtime") + +# Points to toolchain[":toolchain_type"] (was :legacy_current_java_toolchain) +java_toolchain_alias(name = "current_java_toolchain") + +# Aliases value of --plugins flag as a JavaPluginInfo +java_plugins_flag_alias( + name = "java_plugins_flag_alias", +) + +# This is necessary to get the *host* Java runtime. Depending on +# //tools/jdk:current_java_runtime from an attribute with the host transition +# does not work because the dependency is determined based on the configuration +# *before* the transition. +alias( + name = "java_runtime_alias", + actual = "//tools/jdk:current_java_runtime", +) + +# These individual jni_* targets are exposed for legacy reasons. +# Most users should depend on :jni. + +java_runtime_files( + name = "jni_header", + srcs = ["include/jni.h"], +) + +java_runtime_files( + name = "jni_md_header-darwin", + srcs = ["include/darwin/jni_md.h"], +) + +java_runtime_files( + name = "jni_md_header-linux", + srcs = ["include/linux/jni_md.h"], +) + +java_runtime_files( + name = "jni_md_header-windows", + srcs = ["include/win32/jni_md.h"], +) + +java_runtime_files( + name = "jni_md_header-freebsd", + srcs = ["include/freebsd/jni_md.h"], +) + +java_runtime_files( + name = "jni_md_header-openbsd", + srcs = ["include/openbsd/jni_md.h"], +) + +# The Java native interface. Depend on this package if you #include <jni.h>. +# +# See test_jni in third_party/bazel/src/test/shell/bazel/bazel_java_test.sh for +# an example of using Bazel to build a Java program that calls a C function. +# +# TODO(ilist): use //src:condition:linux when released in Bazel +cc_library( + name = "jni", + hdrs = [":jni_header"] + select({ + "//src/conditions:linux_aarch64": [":jni_md_header-linux"], + "//src/conditions:linux_ppc64le": [":jni_md_header-linux"], + "//src/conditions:linux_s390x": [":jni_md_header-linux"], + "//src/conditions:linux_mips64": [":jni_md_header-linux"], + "//src/conditions:linux_riscv64": [":jni_md_header-linux"], + "//src/conditions:linux_x86_64": [":jni_md_header-linux"], + "//src/conditions:darwin": [":jni_md_header-darwin"], + "//src/conditions:freebsd": [":jni_md_header-freebsd"], + "//src/conditions:openbsd": [":jni_md_header-openbsd"], + "//src/conditions:windows": [":jni_md_header-windows"], + "//conditions:default": [], + }), + includes = ["include"] + select({ + "//src/conditions:linux_aarch64": ["include/linux"], + "//src/conditions:linux_ppc64le": ["include/linux"], + "//src/conditions:linux_s390x": ["include/linux"], + "//src/conditions:linux_mips64": [":include/linux"], + "//src/conditions:linux_riscv64": [":include/linux"], + "//src/conditions:linux_x86_64": ["include/linux"], + "//src/conditions:darwin": ["include/darwin"], + "//src/conditions:freebsd": ["include/freebsd"], + "//src/conditions:openbsd": ["include/openbsd"], + "//src/conditions:windows": ["include/win32"], + "//conditions:default": [], + }), +) + +alias( + name = "java", + actual = "@local_jdk//:java", +) + +alias( + name = "jar", + actual = "@local_jdk//:jar", +) + +alias( + name = "javac", + actual = "@local_jdk//:javac", +) + +alias( + name = "javadoc", + actual = "@local_jdk//:javadoc", +) + +[ + ( + alias( + name = "ijar_prebuilt_binary_%s" % OS, + actual = "@remote_java_tools_%s//:ijar_prebuilt_binary" % OS, + visibility = ["//visibility:private"], + ), + alias( + name = "prebuilt_singlejar_%s" % OS, + actual = "@remote_java_tools_%s//:prebuilt_singlejar" % OS, + visibility = ["//visibility:private"], + ), + ) + for OS in [ + "linux", + "darwin", + "windows", + ] +] + +# On Windows, executables end in ".exe", but the label we reach it through +# must be platform-independent. Thus, we create a little filegroup that +# contains the appropriate platform-dependent file. +alias( + name = "ijar", + actual = ":ijar_prebuilt_binary_or_cc_binary", +) + +alias( + name = "ijar_prebuilt_binary_or_cc_binary", + actual = select({ + "//src/conditions:linux_x86_64": ":ijar_prebuilt_binary_linux", + "//src/conditions:darwin": ":ijar_prebuilt_binary_darwin", + "//src/conditions:windows": ":ijar_prebuilt_binary_windows", + "//conditions:default": "@remote_java_tools//:ijar_cc_binary", + }), +) + +alias( + name = "ijar_prebuilt_binary", + actual = select({ + "//src/conditions:linux_x86_64": ":ijar_prebuilt_binary_linux", + "//src/conditions:darwin": ":ijar_prebuilt_binary_darwin", + "//src/conditions:windows": ":ijar_prebuilt_binary_windows", + }), +) + +# On Windows, Java implementation of singlejar is used. We create a little +# filegroup that contains the appropriate platform-dependent file. +# Once https://github.com/bazelbuild/bazel/issues/2241 is fixed (that is, +# the native singlejar is used on windows), this file group can be reused since +# on Windows, executables end in ".exe", but the label we reach it through +# must be platform-independent. +alias( + name = "singlejar", + actual = ":singlejar_prebuilt_or_cc_binary", +) + +alias( + name = "singlejar_prebuilt_or_cc_binary", + actual = select({ + "//src/conditions:linux_x86_64": ":prebuilt_singlejar_linux", + "//src/conditions:darwin": ":prebuilt_singlejar_darwin", + "//src/conditions:windows": ":prebuilt_singlejar_windows", + "//conditions:default": "@remote_java_tools//:singlejar_cc_bin", + }), +) + +alias( + name = "prebuilt_singlejar", + actual = select({ + "//src/conditions:linux_x86_64": ":prebuilt_singlejar_linux", + "//src/conditions:darwin": ":prebuilt_singlejar_darwin", + "//src/conditions:windows": ":prebuilt_singlejar_windows", + }), +) + +exports_files(["BUILD.java_tools"]) + +alias( + name = "genclass", + actual = "@remote_java_tools//:GenClass", +) + +alias( + name = "GenClass_deploy.jar", + actual = "@remote_java_tools//:GenClass", +) + +alias( + name = "turbine", + actual = "@remote_java_tools//:Turbine", +) + +alias( + name = "turbine_deploy.jar", + actual = "@remote_java_tools//:Turbine", +) + +alias( + name = "turbine_direct", + actual = "@remote_java_tools//:TurbineDirect", +) + +alias( + name = "turbine_direct_binary_deploy.jar", + actual = "@remote_java_tools//:TurbineDirect", +) + +alias( + name = "javabuilder", + actual = "@remote_java_tools//:JavaBuilder", +) + +alias( + name = "JavaBuilder_deploy.jar", + actual = "@remote_java_tools//:JavaBuilder", +) + +alias( + name = "vanillajavabuilder", + actual = "@remote_java_tools//:VanillaJavaBuilder", +) + +alias( + name = "javac_jar", + actual = "@remote_java_tools//:javac_jar", +) + +alias( + name = "jdk_compiler_jar", + actual = "@remote_java_tools//:jdk_compiler_jar", +) + +alias( + name = "java_compiler_jar", + actual = "@remote_java_tools//:java_compiler_jar", +) + +alias( + name = "JacocoCoverageRunner", + actual = "@remote_java_tools//:jacoco_coverage_runner", +) + +alias( + name = "JacocoCoverage", + actual = "@remote_java_tools//:jacoco_coverage_runner", +) + +java_import( + name = "TestRunner", + jars = ["@remote_java_tools//:Runner"], +) + +alias( + name = "TestRunner_deploy.jar", + actual = "@remote_java_tools//:Runner", +) + +alias( + name = "proguard", + actual = "@remote_java_tools//:proguard", +) + +BOOTCLASS_JARS = [ + "rt.jar", + "resources.jar", + "jsse.jar", + "jce.jar", + "charsets.jar", +] + +# TODO(cushon): this isn't compatible with JDK 9 +alias( + name = "bootclasspath", + actual = "@local_jdk//:bootclasspath", +) + +alias( + name = "jre", + actual = "@local_jdk//:jre", +) + +alias( + name = "jdk", + actual = "@local_jdk//:jdk", +) + +alias( + name = "host_jdk", + actual = ":remote_jdk11", +) + +bootclasspath( + name = "platformclasspath", + src = "DumpPlatformClassPath.java", + host_javabase = "current_java_runtime", + target_javabase = "current_java_runtime", +) + +default_java_toolchain( + name = "toolchain", + configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, + toolchain_definition = False, +) + +alias( + name = "remote_toolchain", + actual = ":toolchain", +) + +RELEASES = (8, 9, 10, 11) + +[ + default_java_toolchain( + name = "toolchain_java%d" % release, + configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, + source_version = "%s" % release, + target_version = "%s" % release, + ) + for release in RELEASES +] + +# A toolchain that targets java 14. +default_java_toolchain( + name = "toolchain_jdk_14", + configuration = dict(), + java_runtime = "@bazel_tools//tools/jdk:remotejdk_14", + source_version = "14", + target_version = "14", +) + +# A toolchain that targets java 15. +default_java_toolchain( + name = "toolchain_jdk_15", + configuration = dict(), + java_runtime = "@bazel_tools//tools/jdk:remotejdk_15", + source_version = "15", + target_version = "15", +) + +# A toolchain that targets java 16. +default_java_toolchain( + name = "toolchain_jdk_16", + configuration = dict(), + java_runtime = "@bazel_tools//tools/jdk:remotejdk_16", + source_version = "16", + target_version = "16", +) + +# A toolchain that targets java 17. +default_java_toolchain( + name = "toolchain_jdk_17", + configuration = dict(), + java_runtime = "@bazel_tools//tools/jdk:remotejdk_17", + source_version = "17", + target_version = "17", +) + +# Deprecated, do not use. +# It will be removed after migration to Java toolchain resolution. +default_java_toolchain( + name = "toolchain_hostjdk8", + configuration = JVM8_TOOLCHAIN_CONFIGURATION, + java_runtime = ":current_host_java_runtime", + source_version = "8", + target_version = "8", + toolchain_definition = False, +) + +default_java_toolchain( + name = "prebuilt_toolchain", + configuration = PREBUILT_TOOLCHAIN_CONFIGURATION, + toolchain_definition = False, +) + +filegroup( + name = "bzl_srcs", + srcs = glob(["*.bzl"]), + visibility = ["//tools:__pkg__"], +) + +py_binary( + name = "proguard_whitelister", + srcs = [ + "proguard_whitelister.py", + ], + deps = [ + "//third_party/py/abseil", + ], +) + +py_test( + name = "proguard_whitelister_test", + srcs = ["proguard_whitelister_test.py"], + data = ["proguard_whitelister_test_input.pgcfg"], + deps = [ + ":proguard_whitelister", + ], +) + +# Aliases for JDKs, so that they are only downloaded when needed. +_JDKS = [ + "remotejdk11_macos", + "remotejdk11_macos_aarch64", + "remotejdk11_win", + "remotejdk11_linux_aarch64", + "remotejdk11_linux", + "remotejdk11_linux_ppc64le", + "remotejdk11_linux_s390x", + "remotejdk15_macos", + "remotejdk15_macos_aarch64", + "remotejdk15_win", + "remotejdk15_linux", + "remotejdk16_macos", + "remotejdk16_macos_aarch64", + "remotejdk16_win", + "remotejdk16_linux", + "remotejdk17_macos", + "remotejdk17_macos_aarch64", + "remotejdk17_win", + "remotejdk17_linux", +] + +[ + alias( + name = JDK, + actual = "@%s//:jdk" % JDK, + visibility = ["//visibility:private"], + ) + for JDK in _JDKS +] + +# A JDK 11 for use as a --host_javabase. +java_runtime_version_alias( + name = "remote_jdk11", + runtime_version = "remotejdk_11", + visibility = ["//visibility:public"], +) + +java_runtime_version_alias( + name = "remotejdk_15", + runtime_version = "remotejdk_15", + visibility = ["//visibility:public"], +) + +java_runtime_version_alias( + name = "remotejdk_16", + runtime_version = "remotejdk_16", + visibility = ["//visibility:public"], +) + +java_runtime_version_alias( + name = "remotejdk_17", + runtime_version = "remotejdk_17", + visibility = ["//visibility:public"], +) + +java_runtime_version_alias( + name = "jdk_8", + runtime_version = "8", + visibility = ["//visibility:public"], +)
diff --git a/toolchains/DumpPlatformClassPath.java b/toolchains/DumpPlatformClassPath.java new file mode 100644 index 0000000..e23ca53 --- /dev/null +++ b/toolchains/DumpPlatformClassPath.java
@@ -0,0 +1,259 @@ +// Copyright 2017 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. + +import com.sun.tools.javac.api.JavacTool; +import com.sun.tools.javac.util.Context; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import javax.tools.JavaFileManager; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; + +/** + * Output a jar file containing all classes on the platform classpath of the given JDK release. + * + * <p>usage: DumpPlatformClassPath <release version> <output jar> <path to target JDK>? + */ +public class DumpPlatformClassPath { + + public static void main(String[] args) throws Exception { + if (args.length != 2) { + System.err.println("usage: DumpPlatformClassPath <output jar> <path to target JDK>"); + System.exit(1); + } + Path output = Paths.get(args[0]); + Path targetJavabase = Paths.get(args[1]); + + int hostMajorVersion = hostMajorVersion(); + boolean ok; + if (hostMajorVersion == 8) { + ok = dumpJDK8BootClassPath(output, targetJavabase); + } else { + ok = dumpJDK9AndNewerBootClassPath(hostMajorVersion, output, targetJavabase); + } + System.exit(ok ? 0 : 1); + } + + // JDK 8 bootclasspath handling. + // * JDK 8 represents a bootclasspath as a search path of jars (rt.jar, etc.). + // * It does not support --release or --system. + static boolean dumpJDK8BootClassPath(Path output, Path targetJavabase) throws IOException { + List<Path> bootClassPathJars = getBootClassPathJars(targetJavabase); + writeClassPathJars(output, bootClassPathJars); + return true; + } + + // JDK > 8 --host_javabase bootclasspath handling. + // (The default --host_javabase is currently JDK 9.) + static boolean dumpJDK9AndNewerBootClassPath( + int hostMajorVersion, Path output, Path targetJavabase) throws IOException { + + // JDK 9 and newer support cross-compiling to older platform versions using the --system + // and --release flags. + // * --system takes the path to a JDK root for JDK 9 and up, and causes the compilation + // to target the APIs from that JDK. + // * --release takes a language level (e.g. '9') and uses the API information baked in to + // the host JDK (in lib/ct.sym). + + // Since --system only supports JDK >= 9, first check of the target JDK defines a JDK 8 + // bootclasspath. + List<Path> bootClassPathJars = getBootClassPathJars(targetJavabase); + if (!bootClassPathJars.isEmpty()) { + writeClassPathJars(output, bootClassPathJars); + return true; + } + + // Initialize a FileManager to process the --system argument, and then read the + // initialized bootclasspath data back out. + + Context context = new Context(); + JavacTool.create() + .getTask( + /* out = */ null, + /* fileManager = */ null, + /* diagnosticListener = */ null, + /* options = */ Arrays.asList("--system", String.valueOf(targetJavabase)), + /* classes = */ null, + /* compilationUnits = */ null, + context); + StandardJavaFileManager fileManager = + (StandardJavaFileManager) context.get(JavaFileManager.class); + + SortedMap<String, InputStream> entries = new TreeMap<>(); + for (JavaFileObject fileObject : + fileManager.list( + StandardLocation.PLATFORM_CLASS_PATH, + "", + EnumSet.of(Kind.CLASS), + /* recurse= */ true)) { + String binaryName = + fileManager.inferBinaryName(StandardLocation.PLATFORM_CLASS_PATH, fileObject); + entries.put(binaryName.replace('.', '/') + ".class", fileObject.openInputStream()); + } + writeEntries(output, entries); + return true; + } + + /** Writes the given entry names and data to a jar archive at the given path. */ + private static void writeEntries(Path output, Map<String, InputStream> entries) + throws IOException { + if (!entries.containsKey("java/lang/Object.class")) { + throw new AssertionError( + "\nCould not find java.lang.Object on bootclasspath; something has gone terribly wrong.\n" + + "Please file a bug: https://github.com/bazelbuild/bazel/issues"); + } + try (OutputStream os = Files.newOutputStream(output); + BufferedOutputStream bos = new BufferedOutputStream(os, 65536); + JarOutputStream jos = new JarOutputStream(bos)) { + entries.entrySet().stream() + .forEachOrdered( + entry -> { + try { + addEntry(jos, entry.getKey(), entry.getValue()); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + } + + /** Collects the entries of the given jar files into a map from jar entry names to their data. */ + private static void writeClassPathJars(Path output, Collection<Path> paths) throws IOException { + List<JarFile> jars = new ArrayList<>(); + for (Path path : paths) { + jars.add(new JarFile(path.toFile())); + } + SortedMap<String, InputStream> entries = new TreeMap<>(); + for (JarFile jar : jars) { + jar.stream() + .filter(p -> p.getName().endsWith(".class")) + .forEachOrdered( + entry -> { + try { + entries.put(entry.getName(), jar.getInputStream(entry)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } + writeEntries(output, entries); + for (JarFile jar : jars) { + jar.close(); + } + } + + /** Returns paths to the entries of a JDK 8-style bootclasspath. */ + private static List<Path> getBootClassPathJars(Path javaHome) throws IOException { + List<Path> jars = new ArrayList<>(); + Path extDir = javaHome.resolve("jre/lib/ext"); + if (Files.exists(extDir)) { + for (Path extJar : Files.newDirectoryStream(extDir, "*.jar")) { + jars.add(extJar); + } + } + for (String jar : + Arrays.asList("rt.jar", "resources.jar", "jsse.jar", "jce.jar", "charsets.jar")) { + Path path = javaHome.resolve("jre/lib").resolve(jar); + if (Files.exists(path)) { + jars.add(path); + } + } + return jars; + } + + // Use a fixed timestamp for deterministic jar output. + private static final long FIXED_TIMESTAMP = + new GregorianCalendar(2010, 0, 1, 0, 0, 0).getTimeInMillis(); + + /** + * Add a jar entry to the given {@link JarOutputStream}, normalizing the entry timestamps to + * ensure deterministic build output. + */ + private static void addEntry(JarOutputStream jos, String name, InputStream input) + throws IOException { + JarEntry je = new JarEntry(name); + je.setTime(FIXED_TIMESTAMP); + je.setMethod(ZipEntry.STORED); + byte[] bytes = toByteArray(input); + // When targeting JDK >= 10, patch the major version so it will be accepted by javac 9 + // TODO(cushon): remove this after updating javac + if (bytes[7] > 53) { + bytes[7] = 53; + } + je.setSize(bytes.length); + CRC32 crc = new CRC32(); + crc.update(bytes); + je.setCrc(crc.getValue()); + jos.putNextEntry(je); + jos.write(bytes); + } + + private static byte[] toByteArray(InputStream is) throws IOException { + byte[] buffer = new byte[8192]; + ByteArrayOutputStream boas = new ByteArrayOutputStream(); + while (true) { + int r = is.read(buffer); + if (r == -1) { + break; + } + boas.write(buffer, 0, r); + } + return boas.toByteArray(); + } + + /** + * Returns the major version of the host Java runtime (e.g. '8' for JDK 8), using {@link + * Runtime#version} if it is available, and otherwise falling back to the {@code + * java.class.version} system. property. + */ + static int hostMajorVersion() { + try { + Method versionMethod = Runtime.class.getMethod("version"); + Object version = versionMethod.invoke(null); + return (int) version.getClass().getMethod("major").invoke(version); + } catch (ReflectiveOperationException e) { + // Runtime.version() isn't available on JDK 8; continue below + } + int version = (int) Double.parseDouble(System.getProperty("java.class.version")); + if (49 <= version && version <= 52) { + return version - (49 - 5); + } + throw new IllegalStateException( + "Unknown Java version: " + System.getProperty("java.specification.version")); + } +}
diff --git a/toolchains/default_java_toolchain.bzl b/toolchains/default_java_toolchain.bzl new file mode 100644 index 0000000..ac8ed5d --- /dev/null +++ b/toolchains/default_java_toolchain.bzl
@@ -0,0 +1,293 @@ +# Copyright 2017 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 rules for creating Java toolchains.""" + +JDK8_JVM_OPTS = [ + "-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)", +] + +# JVM options, without patching java.compiler and jdk.compiler modules. +BASE_JDK9_JVM_OPTS = [ + # Allow JavaBuilder to access internal javac APIs. + "--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.resources=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED", + "--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED", + "--add-opens=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED", + + # quiet warnings from com.google.protobuf.UnsafeUtil, + # see: https://github.com/google/protobuf/issues/3781 + # and: https://github.com/bazelbuild/bazel/issues/5599 + "--add-opens=java.base/java.nio=ALL-UNNAMED", + "--add-opens=java.base/java.lang=ALL-UNNAMED", +] + +JDK9_JVM_OPTS = BASE_JDK9_JVM_OPTS + [ + # override the javac in the JDK. + "--patch-module=java.compiler=$(location @remote_java_tools//:java_compiler_jar)", + "--patch-module=jdk.compiler=$(location @remote_java_tools//:jdk_compiler_jar)", +] + +DEFAULT_JAVACOPTS = [ + "-XDskipDuplicateBridges=true", + "-XDcompilePolicy=simple", + "-g", + "-parameters", + # https://github.com/bazelbuild/java_tools/issues/51#issuecomment-927940699 + "-XepOpt:ReturnValueIgnored:ObjectMethods=false", +] + +# java_toolchain parameters without specifying javac, java.compiler, +# jdk.compiler module, and jvm_opts +_BASE_TOOLCHAIN_CONFIGURATION = dict( + forcibly_disable_header_compilation = False, + genclass = ["@remote_java_tools//:GenClass"], + header_compiler = ["@remote_java_tools//:TurbineDirect"], + header_compiler_direct = ["@remote_java_tools//:TurbineDirect"], + ijar = ["@bazel_tools//tools/jdk:ijar"], + javabuilder = ["@remote_java_tools//:JavaBuilder"], + javac_supports_workers = True, + jacocorunner = "@remote_java_tools//:jacoco_coverage_runner_filegroup", + jvm_opts = BASE_JDK9_JVM_OPTS, + misc = DEFAULT_JAVACOPTS, + singlejar = ["@bazel_tools//tools/jdk:singlejar"], + # Code to enumerate target JVM boot classpath uses host JVM. Because + # java_runtime-s are involved, its implementation is in @bazel_tools. + bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath"], + source_version = "8", + target_version = "8", + reduced_classpath_incompatible_processors = [ + "dagger.hilt.processor.internal.root.RootProcessor", # see b/21307381 + ], +) + +JVM8_TOOLCHAIN_CONFIGURATION = dict( + tools = ["@remote_java_tools//:javac_jar"], + jvm_opts = ["-Xbootclasspath/p:$(location @remote_java_tools//:javac_jar)"], + java_runtime = "@bazel_tools//tools/jdk:jdk_8", +) + +DEFAULT_TOOLCHAIN_CONFIGURATION = dict( + jvm_opts = [ + # Compact strings make JavaBuilder slightly slower. + "-XX:-CompactStrings", + ] + JDK9_JVM_OPTS, + turbine_jvm_opts = [ + # Turbine is not a worker and parallel GC is faster for short-lived programs. + "-XX:+UseParallelOldGC", + ], + tools = [ + "@remote_java_tools//:java_compiler_jar", + "@remote_java_tools//:jdk_compiler_jar", + ], + java_runtime = "@bazel_tools//tools/jdk:remote_jdk11", +) + +# The 'vanilla' toolchain is an unsupported alternative to the default. +# +# It does not provide any of the following features: +# * Error Prone +# * Strict Java Deps +# * Reduced Classpath Optimization +# +# It uses the version of internal javac from the `--host_javabase` JDK instead +# of providing a javac. Internal javac may not be source- or bug-compatible with +# the javac that is provided with other toolchains. +# +# However it does allow using a wider range of `--host_javabase`s, including +# versions newer than the current JDK. +VANILLA_TOOLCHAIN_CONFIGURATION = dict( + javabuilder = ["@remote_java_tools//:VanillaJavaBuilder"], + jvm_opts = [], +) + +# The new toolchain is using all the pre-built tools, including +# singlejar and ijar, even on remote execution. This toolchain +# should be used only when host and execution platform are the +# same, otherwise the binaries will not work on the execution +# platform. +PREBUILT_TOOLCHAIN_CONFIGURATION = dict( + jvm_opts = [ + # Compact strings make JavaBuilder slightly slower. + "-XX:-CompactStrings", + ] + JDK9_JVM_OPTS, + turbine_jvm_opts = [ + # Turbine is not a worker and parallel GC is faster for short-lived programs. + "-XX:+UseParallelOldGC", + ], + tools = [ + "@remote_java_tools//:java_compiler_jar", + "@remote_java_tools//:jdk_compiler_jar", + ], + ijar = ["@bazel_tools//tools/jdk:ijar_prebuilt_binary"], + singlejar = ["@bazel_tools//tools/jdk:prebuilt_singlejar"], + java_runtime = "@bazel_tools//tools/jdk:remote_jdk11", +) + +# The new toolchain is using all the tools from sources. +NONPREBUILT_TOOLCHAIN_CONFIGURATION = dict( + jvm_opts = [ + # Compact strings make JavaBuilder slightly slower. + "-XX:-CompactStrings", + ] + JDK9_JVM_OPTS, + turbine_jvm_opts = [ + # Turbine is not a worker and parallel GC is faster for short-lived programs. + "-XX:+UseParallelOldGC", + ], + tools = [ + "@remote_java_tools//:java_compiler_jar", + "@remote_java_tools//:jdk_compiler_jar", + ], + ijar = ["@remote_java_tools//:ijar_cc_binary"], + singlejar = ["@remote_java_tools//:singlejar_cc_bin"], + java_runtime = "@bazel_tools//tools/jdk:remote_jdk11", +) + +def default_java_toolchain(name, configuration = DEFAULT_TOOLCHAIN_CONFIGURATION, toolchain_definition = True, **kwargs): + """Defines a remote java_toolchain with appropriate defaults for Bazel.""" + + toolchain_args = dict(_BASE_TOOLCHAIN_CONFIGURATION) + toolchain_args.update(configuration) + toolchain_args.update(kwargs) + native.java_toolchain( + name = name, + **toolchain_args + ) + if toolchain_definition: + native.config_setting( + name = name + "_version_setting", + values = {"java_language_version": toolchain_args["source_version"]}, + visibility = ["//visibility:private"], + ) + native.toolchain( + name = name + "_definition", + toolchain_type = "@bazel_tools//tools/jdk:toolchain_type", + target_settings = [name + "_version_setting"], + toolchain = name, + ) + +def java_runtime_files(name, srcs): + """Copies the given sources out of the current Java runtime.""" + + native.filegroup( + name = name, + srcs = srcs, + ) + for src in srcs: + native.genrule( + name = "gen_%s" % src, + srcs = ["@bazel_tools//tools/jdk:current_java_runtime"], + toolchains = ["@bazel_tools//tools/jdk:current_java_runtime"], + cmd = "cp $(JAVABASE)/%s $@" % src, + outs = [src], + ) + +def _bootclasspath_impl(ctx): + host_javabase = ctx.attr.host_javabase[java_common.JavaRuntimeInfo] + + # explicitly list output files instead of using TreeArtifact to work around + # https://github.com/bazelbuild/bazel/issues/6203 + classes = [ + "DumpPlatformClassPath.class", + ] + + class_outputs = [ + ctx.actions.declare_file("%s_classes/%s" % (ctx.label.name, clazz)) + for clazz in classes + ] + + args = ctx.actions.args() + args.add("-source") + args.add("8") + args.add("-target") + args.add("8") + args.add("-Xlint:-options") + args.add("-cp") + args.add("%s/lib/tools.jar" % host_javabase.java_home) + args.add("-d") + args.add(class_outputs[0].dirname) + args.add(ctx.file.src) + + ctx.actions.run( + executable = "%s/bin/javac" % host_javabase.java_home, + mnemonic = "JavaToolchainCompileClasses", + inputs = [ctx.file.src] + ctx.files.host_javabase, + outputs = class_outputs, + arguments = [args], + ) + + bootclasspath = ctx.outputs.output_jar + + inputs = class_outputs + ctx.files.host_javabase + + args = ctx.actions.args() + args.add("-XX:+IgnoreUnrecognizedVMOptions") + 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_joined( + "-cp", + [class_outputs[0].dirname, "%s/lib/tools.jar" % host_javabase.java_home], + join_with = ctx.configuration.host_path_separator, + ) + args.add("DumpPlatformClassPath") + args.add(bootclasspath) + + if ctx.attr.target_javabase: + inputs.extend(ctx.files.target_javabase) + args.add(ctx.attr.target_javabase[java_common.JavaRuntimeInfo].java_home) + + ctx.actions.run( + executable = str(host_javabase.java_executable_exec_path), + mnemonic = "JavaToolchainCompileBootClasspath", + inputs = inputs, + outputs = [bootclasspath], + arguments = [args], + ) + return [ + DefaultInfo(files = depset([bootclasspath])), + OutputGroupInfo(jar = [bootclasspath]), + ] + +_bootclasspath = rule( + implementation = _bootclasspath_impl, + attrs = { + "host_javabase": attr.label( + cfg = "host", + providers = [java_common.JavaRuntimeInfo], + ), + "src": attr.label( + cfg = "host", + allow_single_file = True, + ), + "target_javabase": attr.label( + providers = [java_common.JavaRuntimeInfo], + ), + "output_jar": attr.output(mandatory = True), + }, +) + +def bootclasspath(name, **kwargs): + _bootclasspath( + name = name, + output_jar = name + ".jar", + **kwargs + )
diff --git a/toolchains/fail_rule.bzl b/toolchains/fail_rule.bzl new file mode 100644 index 0000000..a8a3da2 --- /dev/null +++ b/toolchains/fail_rule.bzl
@@ -0,0 +1,35 @@ +# Copyright 2020 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. + +"""A rule than fails during analysis.""" + +def _fail_rule_impl(ctx): + if ctx.attr.header: + fail("%s %s" % (ctx.attr.header, ctx.attr.message)) + else: + fail(ctx.attr.message) + +fail_rule = rule( + doc = "A rule that fails during analysis.", + implementation = _fail_rule_impl, + attrs = { + "header": attr.string( + doc = "Header of the message.", + ), + "message": attr.string( + mandatory = True, + doc = "Message to display.", + ), + }, +)
diff --git a/toolchains/java_toolchain_alias.bzl b/toolchains/java_toolchain_alias.bzl new file mode 100644 index 0000000..ddf6d3f --- /dev/null +++ b/toolchains/java_toolchain_alias.bzl
@@ -0,0 +1,112 @@ +# Copyright 2019 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. + +"""Experimental re-implementations of Java toolchain aliases using toolchain resolution.""" + +def _java_runtime_alias(ctx): + """An experimental implementation of java_runtime_alias using toolchain resolution.""" + toolchain_info = ctx.toolchains["@bazel_tools//tools/jdk:runtime_toolchain_type"] + toolchain = toolchain_info.java_runtime + return [ + toolchain_info, + toolchain, + platform_common.TemplateVariableInfo({ + "JAVA": str(toolchain.java_executable_exec_path), + "JAVABASE": str(toolchain.java_home), + }), + # See b/65239471 for related discussion of handling toolchain runfiles/data. + DefaultInfo( + runfiles = ctx.runfiles(transitive_files = toolchain.files), + files = toolchain.files, + ), + ] + +java_runtime_alias = rule( + implementation = _java_runtime_alias, + toolchains = ["@bazel_tools//tools/jdk:runtime_toolchain_type"], + incompatible_use_toolchain_transition = True, +) + +def _java_host_runtime_alias(ctx): + """An experimental implementation of java_host_runtime_alias using toolchain resolution.""" + runtime = ctx.attr._runtime + java_runtime = runtime[java_common.JavaRuntimeInfo] + template_variable_info = runtime[platform_common.TemplateVariableInfo] + toolchain_info = platform_common.ToolchainInfo(java_runtime = java_runtime) + return [ + java_runtime, + template_variable_info, + toolchain_info, + runtime[DefaultInfo], + ] + +java_host_runtime_alias = rule( + implementation = _java_host_runtime_alias, + attrs = { + "_runtime": attr.label( + default = Label("@bazel_tools//tools/jdk:current_java_runtime"), + providers = [ + java_common.JavaRuntimeInfo, + platform_common.TemplateVariableInfo, + ], + cfg = "host", + ), + }, + provides = [ + java_common.JavaRuntimeInfo, + platform_common.TemplateVariableInfo, + platform_common.ToolchainInfo, + ], +) + +def _java_runtime_transition_impl(settings, attr): + return {"//command_line_option:java_runtime_version": attr.runtime_version} + +_java_runtime_transition = transition( + implementation = _java_runtime_transition_impl, + inputs = [], + outputs = ["//command_line_option:java_runtime_version"], +) + +java_runtime_version_alias = rule( + implementation = _java_runtime_alias, + toolchains = ["@bazel_tools//tools/jdk:runtime_toolchain_type"], + incompatible_use_toolchain_transition = True, + attrs = { + "runtime_version": attr.string(mandatory = True), + "_allowlist_function_transition": attr.label( + default = "@bazel_tools//tools/allowlists/function_transition_allowlist", + ), + }, + cfg = _java_runtime_transition, +) + +def _java_toolchain_alias(ctx): + """An experimental implementation of java_toolchain_alias using toolchain resolution.""" + toolchain_info = ctx.toolchains["@bazel_tools//tools/jdk:toolchain_type"] + toolchain = toolchain_info.java + return struct( + providers = [ + toolchain_info, + toolchain, + ], + # Use the legacy provider syntax for compatibility with the native rules. + java_toolchain = toolchain, + ) + +java_toolchain_alias = rule( + implementation = _java_toolchain_alias, + toolchains = ["@bazel_tools//tools/jdk:toolchain_type"], + incompatible_use_toolchain_transition = True, +)
diff --git a/toolchains/jdk.BUILD b/toolchains/jdk.BUILD new file mode 100644 index 0000000..6870771 --- /dev/null +++ b/toolchains/jdk.BUILD
@@ -0,0 +1,218 @@ +load("@rules_java//java:defs.bzl", "java_import", "java_runtime") + +package(default_visibility = ["//visibility:public"]) + +exports_files(["BUILD.bazel"]) + +DEPRECATION_MESSAGE = ("Don't depend on targets in the JDK workspace;" + + " use @bazel_tools//tools/jdk:current_java_runtime instead" + + " (see https://github.com/bazelbuild/bazel/issues/5594)") + +filegroup( + name = "jni_header", + srcs = ["include/jni.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jni_md_header-darwin", + srcs = ["include/darwin/jni_md.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jni_md_header-linux", + srcs = ["include/linux/jni_md.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jni_md_header-freebsd", + srcs = ["include/freebsd/jni_md.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jni_md_header-openbsd", + srcs = ["include/openbsd/jni_md.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jni_md_header-windows", + srcs = ["include/win32/jni_md.h"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "java", + srcs = select({ + ":windows": ["bin/java.exe"], + "//conditions:default": ["bin/java"], + }), + data = [":jdk"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jar", + srcs = select({ + ":windows": ["bin/jar.exe"], + "//conditions:default": ["bin/jar"], + }), + data = [":jdk"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "javac", + srcs = select({ + ":windows": ["bin/javac.exe"], + "//conditions:default": ["bin/javac"], + }), + data = [":jdk"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "javadoc", + srcs = select({ + ":windows": ["bin/javadoc.exe"], + "//conditions:default": ["bin/javadoc"], + }), + data = [":jdk"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "xjc", + srcs = ["bin/xjc"], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "wsimport", + srcs = ["bin/wsimport"], + deprecation = DEPRECATION_MESSAGE, +) + +BOOTCLASS_JARS = [ + "rt.jar", + "resources.jar", + "jsse.jar", + "jce.jar", + "charsets.jar", +] + +# TODO(cushon): this isn't compatible with JDK 9 +filegroup( + name = "bootclasspath", + srcs = ["jre/lib/%s" % jar for jar in BOOTCLASS_JARS], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jre-bin", + srcs = select({ + # In some configurations, Java browser plugin is considered harmful and + # common antivirus software blocks access to npjp2.dll interfering with Bazel, + # so do not include it in JRE on Windows. + ":windows": glob( + ["jre/bin/**"], + allow_empty = True, + exclude = ["jre/bin/plugin2/**"], + ), + "//conditions:default": glob( + ["jre/bin/**"], + allow_empty = True, + ), + }), + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jre-lib", + srcs = glob( + ["jre/lib/**"], + allow_empty = True, + ), +) + +filegroup( + name = "jre", + srcs = [":jre-default"], +) + +filegroup( + name = "jre-default", + srcs = [ + ":jre-bin", + ":jre-lib", + ], + deprecation = DEPRECATION_MESSAGE, +) + +filegroup( + name = "jdk-bin", + srcs = glob( + ["bin/**"], + # The JDK on Windows sometimes contains a directory called + # "%systemroot%", which is not a valid label. + exclude = ["**/*%*/**"], + ), +) + +#This folder holds security policies +filegroup( + name = "jdk-conf", + srcs = glob( + ["conf/**"], + allow_empty = True, + ), +) + +filegroup( + name = "jdk-include", + srcs = glob(["include/**"]), +) + +filegroup( + name = "jdk-lib", + srcs = glob( + ["lib/**"], + exclude = [ + "lib/missioncontrol/**", + "lib/visualvm/**", + ], + ), +) + +java_runtime( + name = "jdk", + srcs = [ + ":jdk-bin", + ":jdk-conf", + ":jdk-include", + ":jdk-lib", + ":jre-default", + ], +) + +filegroup( + name = "langtools", + srcs = ["lib/tools.jar"], + deprecation = DEPRECATION_MESSAGE, +) + +java_import( + name = "langtools-neverlink", + deprecation = DEPRECATION_MESSAGE, + jars = ["lib/tools.jar"], + neverlink = 1, +) + +config_setting( + name = "windows", + values = {"cpu": "x64_windows"}, + visibility = ["//visibility:private"], +)
diff --git a/toolchains/local_java_repository.bzl b/toolchains/local_java_repository.bzl new file mode 100644 index 0000000..4c0a433 --- /dev/null +++ b/toolchains/local_java_repository.bzl
@@ -0,0 +1,232 @@ +# Copyright 2020 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. + +"""Rules for importing and registering a local JDK.""" + +load(":default_java_toolchain.bzl", "JVM8_TOOLCHAIN_CONFIGURATION", "default_java_toolchain") + +def _detect_java_version(repository_ctx, java_bin): + properties_out = repository_ctx.execute([java_bin, "-XshowSettings:properties"]).stderr + # This returns an indented list of properties separated with newlines: + # " java.vendor.url.bug = ... \n" + # " java.version = 11.0.8\n" + # " java.version.date = 2020-11-05\" + + strip_properties = [property.strip() for property in properties_out.splitlines()] + version_property = [property for property in strip_properties if property.startswith("java.version = ")] + if len(version_property) != 1: + return None + + version_value = version_property[0][len("java.version = "):] + parts = version_value.split(".") + major = parts[0] + if len(parts) == 1: + return major + elif major == "1": # handles versions below 1.8 + minor = parts[1] + return minor + return major + +def local_java_runtime(name, java_home, version, runtime_name = None, visibility = ["//visibility:public"]): + """Defines a java_runtime target together with Java runtime and compile toolchain definitions. + + Java runtime toolchain is constrained by flag --java_runtime_version having + value set to either name or version argument. + + Java compile toolchains are created for --java_language_version flags values + between 8 and version (inclusive). Java compile toolchains use the same + (local) JDK for compilation. This requires a different configuration for JDK8 + than the newer versions. + + Args: + name: name of the target. + java_home: Path to the JDK. + version: Version of the JDK. + runtime_name: name of java_runtime target if it already exists. + visibility: Visibility that will be applied to the java runtime target + """ + if runtime_name == None: + runtime_name = name + native.java_runtime( + name = runtime_name, + java_home = java_home, + visibility = visibility, + ) + + native.config_setting( + name = name + "_name_setting", + values = {"java_runtime_version": name}, + visibility = ["//visibility:private"], + ) + native.config_setting( + name = name + "_version_setting", + values = {"java_runtime_version": version}, + visibility = ["//visibility:private"], + ) + native.config_setting( + name = name + "_name_version_setting", + values = {"java_runtime_version": name + "_" + version}, + visibility = ["//visibility:private"], + ) + native.alias( + name = name + "_settings_alias", + actual = select({ + name + "_name_setting": name + "_name_setting", + name + "_version_setting": name + "_version_setting", + "//conditions:default": name + "_name_version_setting", + }), + visibility = ["//visibility:private"], + ) + native.toolchain( + name = "runtime_toolchain_definition", + target_settings = [":%s_settings_alias" % name], + toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", + toolchain = runtime_name, + ) + + if version == "8": + default_java_toolchain( + name = name + "_toolchain_java8", + configuration = JVM8_TOOLCHAIN_CONFIGURATION, + source_version = version, + target_version = version, + java_runtime = runtime_name, + ) + elif type(version) == type("") and version.isdigit() and int(version) > 8: + for version in range(8, int(version) + 1): + default_java_toolchain( + name = name + "_toolchain_java" + str(version), + source_version = str(version), + target_version = str(version), + java_runtime = runtime_name, + ) + + # else version is not recognized and no compilation toolchains are predefined + +def _local_java_repository_impl(repository_ctx): + """Repository rule local_java_repository implementation. + + Args: + repository_ctx: repository context + """ + java_home = repository_ctx.attr.java_home + java_home_path = repository_ctx.path(java_home) + if not java_home_path.exists: + fail('The path indicated by the "java_home" attribute "%s" (absolute: "%s") ' + + "does not exist." % (java_home, str(java_home_path))) + + repository_ctx.file( + "WORKSPACE", + "# DO NOT EDIT: automatically generated WORKSPACE file for local_java_repository\n" + + "workspace(name = \"{name}\")\n".format(name = repository_ctx.name), + ) + + extension = ".exe" if repository_ctx.os.name.lower().find("windows") != -1 else "" + java_bin = java_home_path.get_child("bin").get_child("java" + extension) + + if not java_bin.exists: + # Java binary does not exist + repository_ctx.file( + "BUILD.bazel", + _NOJDK_BUILD_TPL.format( + local_jdk = repository_ctx.name, + java_binary = "bin/java" + extension, + java_home = java_home, + ), + False, + ) + return + + # Detect version + version = repository_ctx.attr.version if repository_ctx.attr.version != "" else _detect_java_version(repository_ctx, java_bin) + + # Prepare BUILD file using "local_java_runtime" macro + build_file = "" + if repository_ctx.attr.build_file != None: + build_file = repository_ctx.read(repository_ctx.path(repository_ctx.attr.build_file)) + + runtime_name = '"jdk"' if repository_ctx.attr.build_file else None + local_java_runtime_macro = """ +local_java_runtime( + name = "%s", + runtime_name = %s, + java_home = "%s", + version = "%s", +) +""" % (repository_ctx.name, runtime_name, java_home, version) + + repository_ctx.file( + "BUILD.bazel", + 'load("@bazel_tools//tools/jdk:local_java_repository.bzl", "local_java_runtime")\n' + + build_file + + local_java_runtime_macro, + ) + + # Symlink all files + for file in repository_ctx.path(java_home).readdir(): + repository_ctx.symlink(file, file.basename) + +# Build file template, when JDK does not exist +_NOJDK_BUILD_TPL = '''load("@bazel_tools//tools/jdk:fail_rule.bzl", "fail_rule") +fail_rule( + name = "jdk", + header = "Auto-Configuration Error:", + message = ("Cannot find Java binary {java_binary} in {java_home}; either correct your JAVA_HOME, " + + "PATH or specify Java from remote repository (e.g. " + + "--java_runtime_version=remotejdk_11") +) +config_setting( + name = "localjdk_setting", + values = {{"java_runtime_version": "{local_jdk}"}}, + visibility = ["//visibility:private"], +) +toolchain( + name = "runtime_toolchain_definition", + target_settings = [":localjdk_setting"], + toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", + toolchain = ":jdk", +) +''' + +_local_java_repository_rule = repository_rule( + implementation = _local_java_repository_impl, + local = True, + configure = True, + attrs = { + "java_home": attr.string(), + "version": attr.string(), + "build_file": attr.label(), + }, +) + +def local_java_repository(name, java_home, version = "", build_file = None): + """Registers a runtime toolchain for local JDK and creates an unregistered compile toolchain. + + Toolchain resolution is constrained with --java_runtime_version flag + having value of the "name" or "version" parameter. + + Java compile toolchains are created for --java_language_version flags values + between 8 and version (inclusive). Java compile toolchains use the same + (local) JDK for compilation. + + If there is no JDK "virtual" targets are created, which fail only when actually needed. + + Args: + name: A unique name for this rule. + java_home: Location of the JDK imported. + build_file: optionally BUILD file template + version: optionally java version + """ + _local_java_repository_rule(name = name, java_home = java_home, version = version, build_file = build_file) + native.register_toolchains("@" + name + "//:runtime_toolchain_definition")