diff options
-rw-r--r-- | src/java_tools/buildjar/BUILD | 9 | ||||
-rw-r--r-- | src/main/tools/jdk.BUILD | 1 | ||||
-rw-r--r-- | src/test/shell/bazel/BUILD | 2 | ||||
-rw-r--r-- | tools/jdk/BUILD | 26 | ||||
-rw-r--r-- | tools/jdk/DumpPlatformClassPath.java | 143 | ||||
-rw-r--r-- | tools/jdk/default_java_toolchain.bzl | 8 |
6 files changed, 183 insertions, 6 deletions
diff --git a/src/java_tools/buildjar/BUILD b/src/java_tools/buildjar/BUILD index 0d11de9bd0..ca8d4eb3b4 100644 --- a/src/java_tools/buildjar/BUILD +++ b/src/java_tools/buildjar/BUILD @@ -59,11 +59,16 @@ java_library( ], ) +# This toolchain is used to bootstrap Bazel. java_toolchain( name = "bootstrap_toolchain", - bootclasspath = ["//tools/jdk:bootclasspath"], + # javac -extdirs is implemented by appending the contents to the platform + # class path after -bootclasspath. For convenience, we currently have a + # single jar that contains the contents of both the bootclasspath and + # extdirs. + bootclasspath = ["//tools/jdk:platformclasspath-impl.jar"], encoding = "UTF-8", - extclasspath = ["//tools/jdk:extclasspath"], + extclasspath = [], genclass = ["bootstrap_genclass_deploy.jar"], ijar = ["//third_party/ijar"], javabuilder = ["bootstrap_deploy.jar"], diff --git a/src/main/tools/jdk.BUILD b/src/main/tools/jdk.BUILD index ac7a6bbf29..6726e0424f 100644 --- a/src/main/tools/jdk.BUILD +++ b/src/main/tools/jdk.BUILD @@ -77,6 +77,7 @@ BOOTCLASS_JARS = [ "charsets.jar", ] +# TODO(cushon): this isn't compatible with JDK 9 filegroup( name = "bootclasspath", srcs = ["jre/lib/%s" % jar for jar in BOOTCLASS_JARS], diff --git a/src/test/shell/bazel/BUILD b/src/test/shell/bazel/BUILD index 7cc1f6fe4b..f67c4b2123 100644 --- a/src/test/shell/bazel/BUILD +++ b/src/test/shell/bazel/BUILD @@ -40,8 +40,6 @@ filegroup( "//third_party/java/jdk/langtools:test-srcs", "//tools:srcs", "@local_jdk//:bootclasspath", - # TODO(cushon): migrate to extclasspath and delete - "@local_jdk//:extdir", "@local_jdk//:jdk", ] + select({ # TODO(bazel-team): Once https://github.com/bazelbuild/bazel/issues/2241 diff --git a/tools/jdk/BUILD b/tools/jdk/BUILD index 7ebec85b58..26a236f598 100644 --- a/tools/jdk/BUILD +++ b/tools/jdk/BUILD @@ -138,6 +138,7 @@ BOOTCLASS_JARS = [ "charsets.jar", ] +# TODO(cushon): this isn't compatible with JDK 9 alias( name = "bootclasspath", actual = "@local_jdk//:bootclasspath", @@ -180,6 +181,30 @@ alias( actual = "@local_jdk//:jdk", ) +genrule( + name = "gen_platformclasspath", + srcs = ["DumpPlatformClassPath.java"], + outs = ["platformclasspath-impl.jar"], + cmd = """ +set -eu +TMPDIR=$$(mktemp -d) +$(JAVABASE)/bin/javac $< -d $$TMPDIR +$(JAVA) -cp $$TMPDIR DumpPlatformClassPath 8 $@ +rm -rf $$TMPDIR +""", + toolchains = ["@bazel_tools//tools/jdk:current_host_java_runtime"], + tools = ["@bazel_tools//tools/jdk:current_host_java_runtime"], +) + +# run ijar separately so we can skip it for bootstrapping +genrule( + name = "platformclasspath", + srcs = ["platformclasspath-impl.jar"], + outs = ["platformclasspath.jar"], + cmd = "$(location @bazel_tools//tools/jdk:ijar) $< $@", + tools = ["@bazel_tools//tools/jdk:ijar"], +) + default_java_toolchain( name = "toolchain_jdk8", jvm_opts = JDK8_JVM_OPTS, @@ -199,6 +224,7 @@ filegroup( name = "srcs", srcs = [ "BUILD-jdk", # Tools are build from the workspace for tests. + "DumpPlatformClassPath.java", "alias_rules.bzl", "default_java_toolchain.bzl", "proguard_whitelister.py", diff --git a/tools/jdk/DumpPlatformClassPath.java b/tools/jdk/DumpPlatformClassPath.java new file mode 100644 index 0000000000..300e288d88 --- /dev/null +++ b/tools/jdk/DumpPlatformClassPath.java @@ -0,0 +1,143 @@ +// 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 static java.nio.charset.StandardCharsets.UTF_8; + +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.GregorianCalendar; +import java.util.jar.JarEntry; +import java.util.jar.JarOutputStream; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import javax.tools.JavaCompiler; +import javax.tools.JavaFileManager.Location; +import javax.tools.JavaFileObject; +import javax.tools.JavaFileObject.Kind; +import javax.tools.StandardJavaFileManager; +import javax.tools.StandardLocation; +import javax.tools.ToolProvider; + +/** + * Output a jar file containing all classes on the JDK 8 platform classpath of the default java + * compiler of the current JDK. + * + * <p>usage: DumpPlatformClassPath <target release> output.jar + */ +public class DumpPlatformClassPath { + + public static void main(String[] args) throws IOException { + if (args.length != 2) { + System.err.println("usage: DumpPlatformClassPath <target release> <output jar>"); + System.exit(1); + } + String targetRelease = args[0]; + try (OutputStream os = Files.newOutputStream(Paths.get(args[1])); + BufferedOutputStream bos = new BufferedOutputStream(os, 65536); + JarOutputStream jos = new JarOutputStream(bos)) { + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, UTF_8); + if (isJdk9OrLater()) { + // this configures the filemanager to use a JDK 8 bootclasspath + compiler.getTask( + null, fileManager, null, Arrays.asList("--release", targetRelease), null, null); + Iterable<Path> paths; + try { + paths = + (Iterable<Path>) + StandardJavaFileManager.class + .getMethod("getLocationAsPaths", Location.class) + .invoke(fileManager, StandardLocation.PLATFORM_CLASS_PATH); + } catch (ReflectiveOperationException e) { + throw new LinkageError(e.getMessage(), e); + } + for (Path path : paths) { + Files.walkFileTree( + path, + new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (file.getFileName().toString().endsWith(".sig")) { + String outputPath = path.relativize(file).toString(); + outputPath = + outputPath.substring(0, outputPath.length() - ".sig".length()) + ".class"; + addEntry(jos, outputPath, Files.readAllBytes(file)); + } + return FileVisitResult.CONTINUE; + } + }); + } + } else { + for (JavaFileObject fileObject : + fileManager.list( + StandardLocation.PLATFORM_CLASS_PATH, + "", + EnumSet.of(Kind.CLASS), + /* recurse= */ true)) { + String binaryName = + fileManager.inferBinaryName(StandardLocation.PLATFORM_CLASS_PATH, fileObject); + addEntry( + jos, + binaryName.replace('.', '/') + ".class", + toByteArray(fileObject.openInputStream())); + } + } + } + } + + // Use a fixed timestamp for deterministic jar output. + private static final long FIXED_TIMESTAMP = + new GregorianCalendar(2010, 0, 1, 0, 0, 0).getTimeInMillis(); + + private static void addEntry(JarOutputStream jos, String name, byte[] bytes) throws IOException { + JarEntry je = new JarEntry(name); + je.setTime(FIXED_TIMESTAMP); + je.setMethod(ZipEntry.STORED); + 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(); + } + + private static boolean isJdk9OrLater() { + return Double.parseDouble(System.getProperty("java.class.version")) >= 53.0; + } +} diff --git a/tools/jdk/default_java_toolchain.bzl b/tools/jdk/default_java_toolchain.bzl index ca5615b61d..f6a91ead78 100644 --- a/tools/jdk/default_java_toolchain.bzl +++ b/tools/jdk/default_java_toolchain.bzl @@ -51,10 +51,14 @@ DEFAULT_JAVACOPTS = [ ] DEFAULT_TOOLCHAIN_CONFIGURATION = { - "bootclasspath": [":bootclasspath"], + # javac -extdirs is implemented by appending the contents to the platform + # class path after -bootclasspath. For convenience, we currently have a + # single jar that contains the contents of both the bootclasspath and + # extdirs. + "bootclasspath": ["platformclasspath.jar"], + "extclasspath": [], "compatible_javacopts": DEFAULT_COMPATIBLE_JAVACOPTS, "encoding": "UTF-8", - "extclasspath": [], "forcibly_disable_header_compilation": 0, "genclass": ["@bazel_tools//tools/jdk:genclass"], "header_compiler": ["@bazel_tools//tools/jdk:turbine"], |