From 54177d746c44e0117e0c9c068dd5885303111876 Mon Sep 17 00:00:00 2001 From: cushon Date: Fri, 5 Jan 2018 11:35:07 -0800 Subject: Add support for native header outputs to JavaBuilder Add a --native_header_output flag which, if set, causes JavaBuilder to set the equivalent of `javac -h`, and then collect all generated headers and write them to a jar archive at the given path. PiperOrigin-RevId: 180954084 --- .../java/com/google/devtools/build/buildjar/BUILD | 1 + .../build/buildjar/JavaLibraryBuildRequest.java | 46 ++++++---- .../devtools/build/buildjar/OptionsParser.java | 10 +++ .../build/buildjar/SimpleJavaLibraryBuilder.java | 97 ++++++++++++---------- .../build/buildjar/javac/BlazeJavacArguments.java | 6 ++ .../build/buildjar/javac/BlazeJavacMain.java | 5 ++ 6 files changed, 105 insertions(+), 60 deletions(-) diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD index 64d8fa649c..5690a38298 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/BUILD @@ -23,6 +23,7 @@ java_library( deps = [ ":JarOwner", "//third_party:guava", + "//third_party:jsr305", ], ) diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java index c0ba8d976a..0a45152647 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/JavaLibraryBuildRequest.java @@ -60,6 +60,7 @@ public final class JavaLibraryBuildRequest { private final List processorNames; private final Path outputJar; + private final Path nativeHeaderOutput; private final Path classDir; private final Path tempDir; @@ -170,6 +171,7 @@ public final class JavaLibraryBuildRequest { this.classDir = asPath(firstNonNull(optionsParser.getClassDir(), "classes")); this.tempDir = asPath(firstNonNull(optionsParser.getTempDir(), "_tmp")); this.outputJar = asPath(optionsParser.getOutputJar()); + this.nativeHeaderOutput = asPath(optionsParser.getNativeHeaderOutput()); for (Entry> entry : optionsParser.getPostProcessors().entrySet()) { switch (entry.getKey()) { case "jacoco": @@ -253,6 +255,10 @@ public final class JavaLibraryBuildRequest { return outputJar; } + public Path getNativeHeaderOutput() { + return nativeHeaderOutput; + } + public Path getClassDir() { return classDir; } @@ -261,6 +267,10 @@ public final class JavaLibraryBuildRequest { return tempDir; } + public Path getNativeHeaderDir() { + return getTempDir().resolve("native_headers"); + } + public JacocoInstrumentationProcessor getJacocoInstrumentationProcessor() { return jacocoInstrumentationProcessor; } @@ -282,22 +292,26 @@ public final class JavaLibraryBuildRequest { } public BlazeJavacArguments toBlazeJavacArguments(ImmutableList classPath) { - return BlazeJavacArguments.builder() - .classPath(classPath) - .classOutput(getClassDir()) - .bootClassPath( - ImmutableList.builder() - .addAll(getBootClassPath()) - .addAll(getExtClassPath()) - .build()) - .javacOptions(makeJavacArguments()) - .sourceFiles(ImmutableList.copyOf(getSourceFiles())) - .processors(null) - .sourcePath(getSourcePath()) - .sourceOutput(getSourceGenDir()) - .processorPath(getProcessorPath()) - .plugins(getPlugins()) - .build(); + BlazeJavacArguments.Builder builder = + BlazeJavacArguments.builder() + .classPath(classPath) + .classOutput(getClassDir()) + .bootClassPath( + ImmutableList.builder() + .addAll(getBootClassPath()) + .addAll(getExtClassPath()) + .build()) + .javacOptions(makeJavacArguments()) + .sourceFiles(ImmutableList.copyOf(getSourceFiles())) + .processors(null) + .sourcePath(getSourcePath()) + .sourceOutput(getSourceGenDir()) + .processorPath(getProcessorPath()) + .plugins(getPlugins()); + if (getNativeHeaderOutput() != null) { + builder.nativeHeaderOutput(getNativeHeaderDir()); + } + return builder.build(); } /** Constructs a command line that can be used for a javac invocation. */ diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java index 9a7cc7d807..8df2d2d718 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/OptionsParser.java @@ -35,6 +35,7 @@ import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; +import javax.annotation.Nullable; /** * Parses options that the {@link JavaLibraryBuildRequest} needs to construct a build request from @@ -71,6 +72,7 @@ public final class OptionsParser { private final List processorNames = new ArrayList<>(); private String outputJar; + private @Nullable String nativeHeaderOutput; private String classDir; private String tempDir; @@ -184,6 +186,9 @@ public final class OptionsParser { case "--output": outputJar = getArgument(argQueue, arg); break; + case "--native_header_output": + nativeHeaderOutput = getArgument(argQueue, arg); + break; case "--classdir": classDir = getArgument(argQueue, arg); break; @@ -419,6 +424,11 @@ public final class OptionsParser { return outputJar; } + @Nullable + public String getNativeHeaderOutput() { + return nativeHeaderOutput; + } + public String getClassDir() { return classDir; } diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/SimpleJavaLibraryBuilder.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/SimpleJavaLibraryBuilder.java index 7f461c0c7a..d5dd08688d 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/SimpleJavaLibraryBuilder.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/SimpleJavaLibraryBuilder.java @@ -33,6 +33,7 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.util.HashMap; import java.util.Map; +import javax.annotation.Nullable; /** An implementation of the JavaBuilder that uses in-process javac to compile java files. */ public class SimpleJavaLibraryBuilder implements Closeable { @@ -49,30 +50,45 @@ public class SimpleJavaLibraryBuilder implements Closeable { } protected void prepareSourceCompilation(JavaLibraryBuildRequest build) throws IOException { - Path classDirectory = build.getClassDir(); - if (Files.exists(classDirectory)) { - try { - // Necessary for local builds in order to discard previous outputs - cleanupDirectory(classDirectory); - } catch (IOException e) { - throw new IOException("Cannot clean output directory '" + classDirectory + "'", e); - } - } - Files.createDirectories(classDirectory); + cleanupDirectory(build.getClassDir()); setUpSourceJars(build); + cleanupDirectory(build.getSourceGenDir()); + cleanupDirectory(build.getNativeHeaderDir()); + } - // Create sourceGenDir if necessary. - if (build.getSourceGenDir() != null) { - Path sourceGenDir = build.getSourceGenDir(); - if (Files.exists(sourceGenDir)) { - try { - cleanupDirectory(sourceGenDir); - } catch (IOException e) { - throw new IOException("Cannot clean output directory '" + sourceGenDir + "'", e); - } - } - Files.createDirectories(sourceGenDir); + // Necessary for local builds in order to discard previous outputs + private static void cleanupDirectory(@Nullable Path directory) throws IOException { + if (directory == null) { + return; + } + if (!Files.exists(directory)) { + Files.createDirectories(directory); + return; + } + try { + // TODO(b/27069912): handle symlinks + Files.walkFileTree( + directory, + new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) + throws IOException { + if (!dir.equals(directory)) { + Files.delete(dir); + } + return FileVisitResult.CONTINUE; + } + }); + } catch (IOException e) { + throw new IOException("Cannot clean '" + directory + "'", e); } } @@ -116,6 +132,7 @@ public class SimpleJavaLibraryBuilder implements Closeable { result = compileJavaLibrary(build); if (result.isOk()) { buildJar(build); + nativeHeaderOutput(build); } if (!build.getProcessors().isEmpty()) { if (build.getGeneratedSourcesOutputJar() != null) { @@ -144,6 +161,20 @@ public class SimpleJavaLibraryBuilder implements Closeable { } } + public void nativeHeaderOutput(JavaLibraryBuildRequest build) throws IOException { + if (build.getNativeHeaderOutput() == null) { + return; + } + JarCreator jar = new JarCreator(build.getNativeHeaderOutput()); + try { + jar.setNormalize(true); + jar.setCompression(build.compressJar()); + jar.addDirectory(build.getNativeHeaderDir()); + } finally { + jar.execute(); + } + } + /** * Extracts the all source jars from the build request into the temporary directory specified in * the build request. Empties the temporary directory, if it exists. @@ -151,9 +182,7 @@ public class SimpleJavaLibraryBuilder implements Closeable { private void setUpSourceJars(JavaLibraryBuildRequest build) throws IOException { Path sourcesDir = build.getTempDir(); - if (Files.exists(sourcesDir)) { - cleanupDirectory(sourcesDir); - } + cleanupDirectory(sourcesDir); if (build.getSourceJars().isEmpty()) { return; @@ -198,26 +227,6 @@ public class SimpleJavaLibraryBuilder implements Closeable { return fs; } - // TODO(b/27069912): handle symlinks - private static void cleanupDirectory(Path dir) throws IOException { - Files.walkFileTree( - dir, - new SimpleFileVisitor() { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) - throws IOException { - Files.delete(file); - return FileVisitResult.CONTINUE; - } - - @Override - public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { - Files.delete(dir); - return FileVisitResult.CONTINUE; - } - }); - } - @Override public void close() throws IOException { for (FileSystem fs : filesystems.values()) { diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacArguments.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacArguments.java index f4da51ca7a..c187b2a396 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacArguments.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacArguments.java @@ -61,6 +61,10 @@ public abstract class BlazeJavacArguments { /** The class output directory (-d). */ public abstract Path classOutput(); + /** The native header output directory (-h). */ + @Nullable + public abstract Path nativeHeaderOutput(); + /** The generated source output directory (-s). */ @Nullable public abstract Path sourceOutput(); @@ -85,6 +89,8 @@ public abstract class BlazeJavacArguments { Builder classOutput(Path classOutput); + Builder nativeHeaderOutput(Path nativeHeaderOutput); + Builder bootClassPath(ImmutableList bootClassPath); Builder javacOptions(ImmutableList javacOptions); diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java index 1be5335f59..74059d2e4e 100644 --- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java +++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/BlazeJavacMain.java @@ -172,6 +172,11 @@ public class BlazeJavacMain { fileManager.setLocationFromPaths(StandardLocation.CLASS_PATH, arguments.classPath()); fileManager.setLocationFromPaths( StandardLocation.CLASS_OUTPUT, ImmutableList.of(arguments.classOutput())); + if (arguments.nativeHeaderOutput() != null) { + fileManager.setLocationFromPaths( + StandardLocation.NATIVE_HEADER_OUTPUT, + ImmutableList.of(arguments.nativeHeaderOutput())); + } fileManager.setLocationFromPaths(StandardLocation.SOURCE_PATH, arguments.sourcePath()); // TODO(cushon): require an explicit bootclasspath Collection bootClassPath = arguments.bootClassPath(); -- cgit v1.2.3