Skip to content

Commit

Permalink
'DumpPlatformClasspath' now dumps the current JDK's default platform …
Browse files Browse the repository at this point in the history
…classpath

instead of indirecting through javac's bootclasspath handling and attempting
to pin to a particular source version. This is a stop-gap until we can just
use javac's --release flag.

Using the output of DumpPlatformClasspath as the bootclasspath for the default
java_toolchain side-steps issues with @local_jdk (see #5744, #5594).

PiperOrigin-RevId: 207890272
  • Loading branch information
cushon authored and Copybara-Service committed Aug 8, 2018
1 parent 366da4c commit c56699d
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 143 deletions.
2 changes: 1 addition & 1 deletion src/java_tools/buildjar/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ java_toolchain(
# 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"],
bootclasspath = ["//tools/jdk:platformclasspath.jar"],
extclasspath = [],
genclass = ["bootstrap_genclass_deploy.jar"],
ijar = ["//third_party/ijar"],
Expand Down
30 changes: 10 additions & 20 deletions tools/android/BUILD.tools
Original file line number Diff line number Diff line change
Expand Up @@ -97,26 +97,21 @@ java_binary(
)

gen_java_lang_extras_jar_cmd = """
for jar in $(locations @local_jdk//:bootclasspath); do
if [[ "$${jar}" == *"/rt.jar" ]]; then
$(location %s) \
--exclude_build_data \
--dont_change_compression \
--sources $${jar} \
--include_prefixes "java/lang/invoke/" \
--include_prefixes "java/lang/annotation/" \
--output $@
break
fi
done
$(location %s) \
--exclude_build_data \
--dont_change_compression \
--sources $(location @bazel_tools//tools/jdk:platformclasspath) \
--include_prefixes "java/lang/invoke/" \
--include_prefixes "java/lang/annotation/" \
--output $@
"""

# javac needs this Jar to compile lambdas, method references, and type annotations.
# These classes are not part of the android.jar.
genrule(
name = "gen_java_lang_extras_jar",
srcs = [
"@local_jdk//:bootclasspath"
"@bazel_tools//tools/jdk:platformclasspath"
],
tools = select({
"//src/conditions:windows": [":singlejar_javabin"],
Expand Down Expand Up @@ -178,15 +173,10 @@ genrule(
srcs = ["desugar_jdk_libs.jar"],
outs = ["desugared_java8_legacy_libs.jar"],
cmd = """
classpath=()
for j in $(locations //tools/jdk:bootclasspath); do
classpath+=("--classpath_entry")
classpath+=("$${j}")
done
$(location :desugar_java8) \
--input $< \
--output $@ \
"$${classpath[@]}" \
--classpath_entry "$(location @bazel_tools//tools/jdk:platformclasspath)" \
--core_library --allow_empty_bootclasspath \
--nobest_effort_tolerate_missing_deps \
--noemit_dependency_metadata_as_needed \
Expand Down Expand Up @@ -223,7 +213,7 @@ genrule(
--dont_rewrite_core_library_invocation "java/util/Iterator#remove" """,
tools = [
":desugar_java8",
"//tools/jdk:bootclasspath",
"@bazel_tools//tools/jdk:platformclasspath",
],
visibility = ["//visibility:private"],
)
Expand Down
18 changes: 4 additions & 14 deletions tools/jdk/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -169,29 +169,20 @@ alias(
)

genrule(
name = "gen_platformclasspath",
name = "platformclasspath",
srcs = ["DumpPlatformClassPath.java"],
outs = ["platformclasspath-impl.jar"],
outs = ["platformclasspath.jar"],
cmd = """
set -eu
TMPDIR=$$(mktemp -d -t tmp.XXXXXXXX)
$(JAVABASE)/bin/javac $< -d $$TMPDIR
$(JAVA) -cp $$TMPDIR DumpPlatformClassPath 8 $@
$(JAVA) -cp $$TMPDIR DumpPlatformClassPath $@
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_hostjdk8",
bootclasspath = [":platformclasspath"],
Expand All @@ -204,8 +195,7 @@ default_java_toolchain(

default_java_toolchain(
name = "toolchain",
bootclasspath = [":bootclasspath"],
extclasspath = [":extclasspath"],
bootclasspath = [":platformclasspath"],
source_version = "8",
target_version = "8",
)
Expand Down
154 changes: 46 additions & 108 deletions tools/jdk/DumpPlatformClassPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,146 +12,84 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Comparator.comparing;

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.net.URI;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystems;
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.HashMap;
import java.util.Map;
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.
* Output a jar file containing all classes on the platform classpath of the current JDK.
*
* <p>usage: DumpPlatformClassPath <target release> output.jar
* <p>usage: DumpPlatformClassPath <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>");
if (args.length != 1) {
System.err.println("usage: DumpPlatformClassPath <output jar>");
System.exit(1);
}
String targetRelease = args[0];
Map<String, byte[]> entries = new HashMap<>();
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);
for (Path path : getLocationAsPaths(fileManager)) {
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";
entries.put(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);
entries.put(
binaryName.replace('.', '/') + ".class", toByteArray(fileObject.openInputStream()));
}
Path output = Paths.get(args[0]);
Path path = Paths.get(System.getProperty("java.home"));
if (path.endsWith("jre")) {
path = path.getParent();
}
Path rtJar = path.resolve("jre/lib/rt.jar");
System.err.println(rtJar);
if (Files.exists(rtJar)) {
Files.copy(rtJar, output);
return;
}
try (OutputStream os = Files.newOutputStream(Paths.get(args[1]));
Path modules = FileSystems.getFileSystem(URI.create("jrt:/")).getPath("modules");
try (OutputStream os = Files.newOutputStream(output);
BufferedOutputStream bos = new BufferedOutputStream(os, 65536);
JarOutputStream jos = new JarOutputStream(bos)) {
entries
.entrySet()
.stream()
.sorted(comparing(Map.Entry::getKey))
.forEachOrdered(e -> addEntry(jos, e.getKey(), e.getValue()));
}
}

@SuppressWarnings("unchecked")
private static Iterable<Path> getLocationAsPaths(StandardJavaFileManager fileManager) {
try {
return (Iterable<Path>)
StandardJavaFileManager.class
.getMethod("getLocationAsPaths", Location.class)
.invoke(fileManager, StandardLocation.PLATFORM_CLASS_PATH);
} catch (ReflectiveOperationException e) {
throw new LinkageError(e.getMessage(), e);
try (DirectoryStream<Path> modulePaths = Files.newDirectoryStream(modules)) {
for (Path modulePath : modulePaths) {
Files.walkFileTree(
modulePath,
new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)
throws IOException {
String name = path.getFileName().toString();
if (name.endsWith(".class") && !name.equals("module-info.class")) {
addEntry(jos, modulePath.relativize(path).toString(), Files.readAllBytes(path));
}
return super.visitFile(path, attrs);
}
});
}
}
}
}

// 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) {
try {
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);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

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;
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);
}
}

0 comments on commit c56699d

Please sign in to comment.