aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Liam Miller-Cushon <cushon@google.com>2016-02-18 01:45:49 +0000
committerGravatar Damien Martin-Guillerez <dmarting@google.com>2016-02-18 09:57:36 +0000
commite175f3eae6986b18918144d166a2b8028c43857c (patch)
tree5d37cb804ee135bff6ac0b648443c5599cf933f8 /src
parentc8424a6b0a012b7ec757ae2365f369a3d7562645 (diff)
Initial support for Java header compilation
'Turbine' compiles ijars from source, ignoring method bodies and relaxing error checks for performance. We can then do normal compilation against those ijars and move javac off the build's critical path. -- MOS_MIGRATED_REVID=114919013
Diffstat (limited to 'src')
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java94
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java4
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java7
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java330
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java10
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java28
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java114
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java7
-rw-r--r--src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java3
12 files changed, 551 insertions, 71 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 1800b43ea2..08e7789772 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -409,6 +409,7 @@ java_library(
],
deps = [
":concurrent",
+ ":preconditions",
"//src/main/protobuf:build_proto_v2",
"//third_party:guava",
"//third_party:protobuf",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
index c586c6a42f..109b606fea 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/BaseJavaCompilationHelper.java
@@ -132,7 +132,7 @@ public class BaseJavaCompilationHelper {
/**
* Returns the javac bootclasspath artifacts.
*/
- protected final Iterable<Artifact> getBootClasspath() {
+ protected final ImmutableList<Artifact> getBootClasspath() {
return ruleContext.getPrerequisiteArtifacts("$javac_bootclasspath", Mode.HOST).list();
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
index 5500cd7226..63dee12638 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompilationHelper.java
@@ -109,12 +109,7 @@ public final class JavaCompilationHelper extends BaseJavaCompilationHelper {
builder.setClasspathEntries(attributes.getCompileTimeClassPath());
builder.addResources(attributes.getResources());
builder.addClasspathResources(attributes.getClassPathResources());
- // Only add default bootclasspath entries if not explicitly set in attributes.
- if (!attributes.getBootClassPath().isEmpty()) {
- builder.setBootclasspathEntries(attributes.getBootClassPath());
- } else {
- builder.setBootclasspathEntries(getBootClasspath());
- }
+ builder.setBootclasspathEntries(getBootclasspathOrDefault());
builder.setExtdirInputs(getExtdirInputs());
builder.setLangtoolsJar(getLangtoolsJar());
builder.setJavaBuilderJar(getJavaBuilderJar());
@@ -143,6 +138,16 @@ public final class JavaCompilationHelper extends BaseJavaCompilationHelper {
getAnalysisEnvironment().registerAction(builder.build());
}
+ /** Returns the bootclasspath explicit set in attributes if present, or else the default. */
+ private ImmutableList<Artifact> getBootclasspathOrDefault() {
+ JavaTargetAttributes attributes = getAttributes();
+ if (!attributes.getBootClassPath().isEmpty()) {
+ return attributes.getBootClassPath();
+ } else {
+ return getBootClasspath();
+ }
+ }
+
/**
* Creates the Action that compiles Java source files and optionally instruments them for
* coverage.
@@ -196,6 +201,67 @@ public final class JavaCompilationHelper extends BaseJavaCompilationHelper {
getRuleContext().getLabel().toString());
}
+ private boolean shouldUseHeaderCompilation() {
+ if (!getJavaConfiguration().useHeaderCompilation()) {
+ return false;
+ }
+ if (!attributes.hasSourceFiles() && !attributes.hasSourceJars()) {
+ return false;
+ }
+ if (JavaToolchainProvider.getHeaderCompilerJar(getRuleContext()) == null) {
+ getRuleContext().ruleError(
+ "header compilation was requested but it is not support by the current Java toolchain;"
+ + " see the java_toolchain.header_compiler attribute");
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates the Action that compiles ijars from source.
+ *
+ * @param runtimeJar the jar output of this java compilation, used to create output-relative
+ * paths for new artifacts.
+ */
+ private Artifact createHeaderCompilationAction(
+ Artifact runtimeJar, JavaCompilationArtifacts.Builder artifactBuilder) {
+
+ Artifact headerJar =
+ getAnalysisEnvironment()
+ .getDerivedArtifact(
+ FileSystemUtils.replaceExtension(runtimeJar.getRootRelativePath(), "-hjar.jar"),
+ runtimeJar.getRoot());
+ Artifact headerDeps =
+ getAnalysisEnvironment()
+ .getDerivedArtifact(
+ FileSystemUtils.replaceExtension(runtimeJar.getRootRelativePath(), "-hjar.jdeps"),
+ runtimeJar.getRoot());
+
+ JavaTargetAttributes attributes = getAttributes();
+ JavaHeaderCompileActionBuilder builder = new JavaHeaderCompileActionBuilder(getRuleContext());
+ builder.addSourceFiles(attributes.getSourceFiles());
+ builder.addSourceJars(attributes.getSourceJars());
+ builder.setClasspathEntries(attributes.getCompileTimeClassPath());
+ builder.addAllBootclasspathEntries(getBootclasspathOrDefault());
+ builder.addAllExtClasspathEntries(getExtdirInputs());
+ // TODO(cushon): restrict to only API-generating annotation processors
+ builder.addProcessorPaths(attributes.getProcessorPath());
+ builder.addProcessorNames(attributes.getProcessorNames());
+ builder.setJavacOpts(getJavacOpts());
+ builder.setTempDirectory(tempDir(headerJar));
+ builder.setOutputJar(headerJar);
+ builder.setOutputDepsProto(headerDeps);
+ builder.setStrictJavaDeps(attributes.getStrictJavaDeps());
+ builder.addCompileTimeDependencyArtifacts(attributes.getCompileTimeDependencyArtifacts());
+ builder.addDirectJars(attributes.getDirectJars());
+ builder.setRuleKind(attributes.getRuleKind());
+ builder.setTargetLabel(attributes.getTargetLabel());
+ builder.build();
+
+ artifactBuilder.setCompileTimeDependencies(headerDeps);
+ return headerJar;
+ }
+
/**
* Returns the artifact for a jar file containing class files that were generated by
* annotation processors.
@@ -228,8 +294,8 @@ public final class JavaCompilationHelper extends BaseJavaCompilationHelper {
* Returns the artifact for the manifest proto emitted from JavaBuilder. For example, for a
* class jar foo.jar, returns "foo.jar_manifest_proto".
*
- * @param outputJar The artifact for the class jar emitted form JavaBuilder
- * @return The output artifact for the manifest proto emitted from JavaBuilder
+ * @param outputJar The artifact for the class jar emitted form JavaBuilder
+ * @return The output artifact for the manifest proto emitted from JavaBuilder
*/
public Artifact createManifestProtoOutput(Artifact outputJar) {
return getRuleContext().getDerivedArtifact(
@@ -396,12 +462,18 @@ public final class JavaCompilationHelper extends BaseJavaCompilationHelper {
* Creates the actions that produce the interface jar. Adds the jar artifacts to the given
* JavaCompilationArtifacts builder.
*
- * @return The ijar (if requested), or class jar (if not)
+ * @return the header jar (if requested), or ijar (if requested), or else the class jar
*/
public Artifact createCompileTimeJarAction(
Artifact runtimeJar, JavaCompilationArtifacts.Builder builder) {
- Artifact jar =
- getJavaConfiguration().getUseIjars() ? createIjarAction(runtimeJar, false) : runtimeJar;
+ Artifact jar;
+ if (shouldUseHeaderCompilation()) {
+ jar = createHeaderCompilationAction(runtimeJar, builder);
+ } else if (getJavaConfiguration().getUseIjars()) {
+ jar = createIjarAction(runtimeJar, false);
+ } else {
+ jar = runtimeJar;
+ }
builder.addCompileTimeJar(jar);
return jar;
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
index d5f346ab15..0d5c6cd35d 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaCompileAction.java
@@ -560,7 +560,7 @@ public class JavaCompileAction extends AbstractAction {
for (Artifact extjar : extdirInputs) {
extdirs.add(extjar.getExecPath().getParentDirectory());
}
- result.add(Joiner.on(configuration.getHostPathSeparator()).join(extdirs));
+ result.add(Joiner.on(configuration.getHostPathSeparator()).join(extdirs));
}
if (!processorPath.isEmpty()) {
@@ -666,7 +666,7 @@ public class JavaCompileAction extends AbstractAction {
* Builds the list of mappings between jars on the classpath and their
* originating targets names.
*/
- private static ImmutableList<String> addJarsToTargets(
+ static ImmutableList<String> addJarsToTargets(
NestedSet<Artifact> classpath, Collection<Artifact> directJars) {
ImmutableList.Builder<String> builder = ImmutableList.builder();
for (Artifact jar : classpath) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
index 8a3c6232bc..8ba74343ef 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
@@ -130,6 +130,7 @@ public final class JavaConfiguration extends Fragment {
private final ImmutableList<String> defaultJavaBuilderJvmOpts;
private final Label javaLangtoolsJar;
private final boolean useIjars;
+ private final boolean useHeaderCompilation;
private final boolean generateJavaDeps;
private final JavaClasspathMode experimentalJavaClasspath;
private final ImmutableList<String> javaWarns;
@@ -161,6 +162,7 @@ public final class JavaConfiguration extends Fragment {
this.defaultJavaBuilderJvmOpts = defaultJavaBuilderJvmOpts;
this.javaLangtoolsJar = javaOptions.javaLangtoolsJar;
this.useIjars = javaOptions.useIjars;
+ this.useHeaderCompilation = javaOptions.headerCompilation;
this.generateJavaDeps = generateJavaDeps;
this.experimentalJavaClasspath = javaOptions.experimentalJavaClasspath;
this.javaWarns = ImmutableList.copyOf(javaOptions.javaWarns);
@@ -241,6 +243,11 @@ public final class JavaConfiguration extends Fragment {
return useIjars;
}
+ /** Returns true iff Java header compilation is enabled. */
+ public boolean useHeaderCompilation() {
+ return useHeaderCompilation;
+ }
+
/**
* Returns true iff dependency information is generated after compilation.
*/
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
new file mode 100644
index 0000000000..671224ae46
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaHeaderCompileActionBuilder.java
@@ -0,0 +1,330 @@
+// Copyright 2016 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.
+
+package com.google.devtools.build.lib.rules.java;
+
+import static com.google.devtools.build.lib.util.Preconditions.checkNotNull;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CommandLine;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomMultiArgv;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
+import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
+import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.vfs.PathFragment;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import javax.annotation.Nullable;
+
+/**
+ * Builder for Java header compilation actions, to be used if --experimental_java_header_compilation
+ * is enabled.
+ *
+ * <p>The header compiler consumes the inputs of a java compilation, and produces an interface
+ * jar that can be used as a compile-time jar by upstream targets. The header interface jar is
+ * equivalent to the output of ijar, but unlike ijar the header compiler operates directly on
+ * Java source files instead post-processing the class outputs of the compilation. Compiling the
+ * interface jar from source moves javac off the build's critical path.
+ *
+ * <p>The implementation of the header compiler tool can be found under
+ * {@code //src/java_tools/buildjar/java/com/google/devtools/build/java/turbine}.
+ */
+public class JavaHeaderCompileActionBuilder {
+
+ static final ResourceSet RESOURCE_SET =
+ ResourceSet.createWithRamCpuIo(/*memoryMb=*/ 750.0, /*cpuUsage=*/ 0.5, /*ioUsage=*/ 0.0);
+
+ private final RuleContext ruleContext;
+
+ private Artifact outputJar;
+ @Nullable private Artifact outputDepsProto;
+ private final Collection<Artifact> sourceFiles = new ArrayList<>();
+ private final Collection<Artifact> sourceJars = new ArrayList<>();
+ private NestedSet<Artifact> classpathEntries = NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER);
+ private List<Artifact> bootclasspathEntries = new ArrayList<>();
+ @Nullable private String ruleKind;
+ @Nullable private Label targetLabel;
+ private PathFragment tempDirectory;
+ private BuildConfiguration.StrictDepsMode strictJavaDeps = BuildConfiguration.StrictDepsMode.OFF;
+ private List<Artifact> directJars = new ArrayList<>();
+ private List<Artifact> compileTimeDependencyArtifacts = new ArrayList<>();
+ private ImmutableList<String> javacOpts;
+ private List<Artifact> processorPath = new ArrayList<>();
+ private List<String> processorNames = new ArrayList<>();
+
+ /** Creates a builder using the configuration of the rule as the action configuration. */
+ public JavaHeaderCompileActionBuilder(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ }
+
+ /** Sets the output jdeps file. */
+ public JavaHeaderCompileActionBuilder setOutputDepsProto(@Nullable Artifact outputDepsProto) {
+ this.outputDepsProto = outputDepsProto;
+ return this;
+ }
+
+ /** Sets the direct dependency artifacts. */
+ public JavaHeaderCompileActionBuilder addDirectJars(Collection<Artifact> directJars) {
+ checkNotNull(directJars, "directJars must not be null");
+ this.directJars.addAll(directJars);
+ return this;
+ }
+
+ /** Sets the .jdeps artifacts for direct dependencies. */
+ public JavaHeaderCompileActionBuilder addCompileTimeDependencyArtifacts(
+ Collection<Artifact> dependencyArtifacts) {
+ checkNotNull(dependencyArtifacts, "dependencyArtifacts must not be null");
+ this.compileTimeDependencyArtifacts.addAll(dependencyArtifacts);
+ return this;
+ }
+
+ /** Sets Java compiler flags. */
+ public JavaHeaderCompileActionBuilder setJavacOpts(ImmutableList<String> javacOpts) {
+ checkNotNull(javacOpts, "javacOpts must not be null");
+ this.javacOpts = javacOpts;
+ return this;
+ }
+
+ /** Sets the output jar. */
+ public JavaHeaderCompileActionBuilder setOutputJar(Artifact outputJar) {
+ checkNotNull(outputJar, "outputJar must not be null");
+ this.outputJar = outputJar;
+ return this;
+ }
+
+ /** Adds a Java source file to compile. */
+ public JavaHeaderCompileActionBuilder addSourceFile(Artifact sourceFile) {
+ checkNotNull(sourceFile, "sourceFile must not be null");
+ sourceFiles.add(sourceFile);
+ return this;
+ }
+
+ /** Adds Java source files to compile. */
+ public JavaHeaderCompileActionBuilder addSourceFiles(Collection<Artifact> sourceFiles) {
+ checkNotNull(sourceFiles, "sourceFiles must not be null");
+ this.sourceFiles.addAll(sourceFiles);
+ return this;
+ }
+
+ /** Adds a jar archive of Java sources to compile. */
+ public JavaHeaderCompileActionBuilder addSourceJars(Collection<Artifact> sourceJars) {
+ checkNotNull(sourceJars, "sourceJars must not be null");
+ this.sourceJars.addAll(sourceJars);
+ return this;
+ }
+
+ /** Sets the compilation classpath entries. */
+ public JavaHeaderCompileActionBuilder setClasspathEntries(NestedSet<Artifact> classpathEntries) {
+ checkNotNull(classpathEntries, "classpathEntries must not be null");
+ this.classpathEntries = classpathEntries;
+ return this;
+ }
+
+ /** Sets the compilation bootclasspath entries. */
+ public JavaHeaderCompileActionBuilder addAllBootclasspathEntries(
+ Collection<Artifact> bootclasspathEntries) {
+ checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
+ this.bootclasspathEntries.addAll(bootclasspathEntries);
+ return this;
+ }
+
+ /** Sets the compilation extclasspath entries. */
+ public JavaHeaderCompileActionBuilder addAllExtClasspathEntries(
+ Collection<Artifact> extclasspathEntries) {
+ checkNotNull(extclasspathEntries, "extclasspathEntries must not be null");
+ // fold extclasspath entries into the bootclasspath; that's what javac ends up doing
+ this.bootclasspathEntries.addAll(extclasspathEntries);
+ return this;
+ }
+
+ /** Sets the annotation processors classpath entries. */
+ public JavaHeaderCompileActionBuilder addProcessorPaths(Collection<Artifact> processorPaths) {
+ checkNotNull(processorPaths, "processorPaths must not be null");
+ this.processorPath.addAll(processorPaths);
+ return this;
+ }
+
+ /** Sets the fully-qualified class names of annotation processors to run. */
+ public JavaHeaderCompileActionBuilder addProcessorNames(Collection<String> processorNames) {
+ checkNotNull(processorNames, "processorNames must not be null");
+ this.processorNames.addAll(processorNames);
+ return this;
+ }
+
+ /** Sets the kind of the build rule being compiled (e.g. {@code java_library}). */
+ public JavaHeaderCompileActionBuilder setRuleKind(@Nullable String ruleKind) {
+ this.ruleKind = ruleKind;
+ return this;
+ }
+
+ /** Sets the label of the target being compiled. */
+ public JavaHeaderCompileActionBuilder setTargetLabel(@Nullable Label targetLabel) {
+ this.targetLabel = targetLabel;
+ return this;
+ }
+
+ /**
+ * Sets the path to a temporary directory, e.g. for extracting sourcejar entries to before
+ * compilation.
+ */
+ public JavaHeaderCompileActionBuilder setTempDirectory(PathFragment tempDirectory) {
+ checkNotNull(tempDirectory, "tempDirectory must not be null");
+ this.tempDirectory = tempDirectory;
+ return this;
+ }
+
+ /** Sets the Strict Java Deps mode. */
+ public JavaHeaderCompileActionBuilder setStrictJavaDeps(StrictDepsMode strictJavaDeps) {
+ checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
+ this.strictJavaDeps = strictJavaDeps;
+ return this;
+ }
+
+ /** Builds and registers the {@link SpawnAction} for a header compilation. */
+ public void build() {
+ checkNotNull(outputDepsProto, "outputDepsProto must not be null");
+ checkNotNull(sourceFiles, "sourceFiles must not be null");
+ checkNotNull(sourceJars, "sourceJars must not be null");
+ checkNotNull(classpathEntries, "classpathEntries must not be null");
+ checkNotNull(bootclasspathEntries, "bootclasspathEntries must not be null");
+ checkNotNull(tempDirectory, "tempDirectory must not be null");
+ checkNotNull(strictJavaDeps, "strictJavaDeps must not be null");
+ checkNotNull(directJars, "directJars must not be null");
+ checkNotNull(compileTimeDependencyArtifacts, "compileTimeDependencyArtifacts must not be null");
+ checkNotNull(javacOpts, "javacOpts must not be null");
+ checkNotNull(processorPath, "processorPath must not be null");
+ checkNotNull(processorNames, "processorNames must not be null");
+
+ SpawnAction.Builder builder = new SpawnAction.Builder();
+
+ builder.addOutput(outputJar);
+ if (outputDepsProto != null) {
+ builder.addOutput(outputDepsProto);
+ }
+
+ builder.useParameterFile(ParameterFileType.SHELL_QUOTED);
+ builder.setCommandLine(buildCommandLine(ruleContext.getConfiguration().getHostPathSeparator()));
+
+ builder.addTransitiveInputs(JavaCompilationHelper.getHostJavabaseInputs(ruleContext));
+ builder.addInputs(classpathEntries);
+ builder.addInputs(bootclasspathEntries);
+ builder.addInputs(processorPath);
+ builder.addInputs(sourceJars);
+ builder.addInputs(sourceFiles);
+ builder.addInputs(directJars);
+ builder.addInputs(compileTimeDependencyArtifacts);
+
+ Artifact langtools = ruleContext.getPrerequisiteArtifact("$java_langtools", Mode.HOST);
+ builder.addTool(langtools);
+
+ List<String> jvmArgs =
+ ImmutableList.<String>builder()
+ .addAll(JavaToolchainProvider.getDefaultJavacJvmOptions(ruleContext))
+ .add("-Xbootclasspath/p:" + langtools.getExecPath().getPathString())
+ .build();
+ builder.setJarExecutable(
+ ruleContext.getHostConfiguration().getFragment(Jvm.class).getJavaExecutable(),
+ JavaToolchainProvider.getHeaderCompilerJar(ruleContext),
+ jvmArgs);
+
+ builder.setResources(RESOURCE_SET);
+
+ builder.setMnemonic("Turbine");
+
+ int count = sourceFiles.size() + sourceJars.size();
+ builder.setProgressMessage(
+ "Compiling Java headers " + outputJar.prettyPrint() + " (" + count + " files)");
+
+ ruleContext.registerAction(builder.build(ruleContext));
+ }
+
+ /** Builds the header compiler command line. */
+ private CommandLine buildCommandLine(String hostPathSeparator) {
+ CustomCommandLine.Builder result = CustomCommandLine.builder();
+
+ result.addExecPath("--output", outputJar);
+
+ if (outputDepsProto != null) {
+ result.addExecPath("--output_deps", outputDepsProto);
+ }
+
+ result.add("--temp_dir").addPath(tempDirectory);
+
+ result.addJoinExecPaths("--classpath", hostPathSeparator, classpathEntries);
+ result.addJoinExecPaths(
+ "--bootclasspath", hostPathSeparator, bootclasspathEntries);
+
+ if (!processorNames.isEmpty()) {
+ result.add("--processors", processorNames);
+ }
+ if (!processorPath.isEmpty()) {
+ result.addJoinExecPaths(
+ "--processorpath", hostPathSeparator, processorPath);
+ }
+
+ result.addExecPaths("--sources", sourceFiles);
+
+ if (!sourceJars.isEmpty()) {
+ result.addExecPaths("--source_jars", sourceJars);
+ }
+
+ result.add("--javacopts", javacOpts);
+
+ if (ruleKind != null) {
+ result.add("--rule_kind");
+ result.add(ruleKind);
+ }
+ if (targetLabel != null) {
+ result.add("--target_label");
+ if (targetLabel.getPackageIdentifier().getRepository().isDefault()) {
+ result.add(targetLabel.toString());
+ } else {
+ // @-prefixed strings will be assumed to be params filenames and expanded,
+ // so add an extra @ to escape it.
+ result.add("@" + targetLabel);
+ }
+ }
+
+ if (strictJavaDeps != BuildConfiguration.StrictDepsMode.OFF) {
+ result.add("--strict_java_deps");
+ result.add(strictJavaDeps.toString());
+ result.add(
+ new CustomMultiArgv() {
+ @Override
+ public Iterable<String> argv() {
+ return JavaCompileAction.addJarsToTargets(classpathEntries, directJars);
+ }
+ });
+
+ if (!compileTimeDependencyArtifacts.isEmpty()) {
+ result.addExecPaths("--deps_artifacts", compileTimeDependencyArtifacts);
+ }
+ }
+
+ return result.build();
+ }
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
index 0a5fcc0455..1785ab9e7b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
@@ -88,7 +88,6 @@ public class JavaOptions extends FragmentOptions {
}
}
-
/** Converter for --singlejar_top. */
public static class SingleJarConverter extends DefaultLabelConverter {
public SingleJarConverter() {
@@ -234,6 +233,14 @@ public class JavaOptions extends FragmentOptions {
help = "No-op. Kept here for backwards compatibility.")
public boolean useSourceIjars;
+ @Option(
+ name = "experimental_java_header_compilation",
+ defaultValue = "false",
+ category = "undocumented",
+ help = "Experimental: compile ijars directly from source."
+ )
+ public boolean headerCompilation;
+
@Deprecated
@Option(name = "experimental_incremental_ijars",
defaultValue = "false",
@@ -413,6 +420,7 @@ public class JavaOptions extends FragmentOptions {
host.javacOpts = javacOpts;
host.javaLangtoolsJar = javaLangtoolsJar;
host.javacExtdir = javacExtdir;
+ host.headerCompilation = headerCompilation;
host.javaBuilderTop = javaBuilderTop;
host.javaToolchain = javaToolchain;
host.singleJarTop = singleJarTop;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
index 97aa87f8e0..27ef1754d7 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchain.java
@@ -13,12 +13,16 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.java;
+import com.google.common.collect.Iterables;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.Runfiles;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.collect.nestedset.Order;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
@@ -42,8 +46,13 @@ public final class JavaToolchain implements RuleConfiguredTargetFactory {
final JavaToolchainData toolchainData =
new JavaToolchainData(source, target, encoding, xlint, misc, jvmOpts);
final JavaConfiguration configuration = ruleContext.getFragment(JavaConfiguration.class);
- JavaToolchainProvider provider = new JavaToolchainProvider(toolchainData,
- configuration.getDefaultJavacFlags(), configuration.getDefaultJavaBuilderJvmFlags());
+ Artifact headerCompiler = getTurbine(ruleContext);
+ JavaToolchainProvider provider =
+ new JavaToolchainProvider(
+ toolchainData,
+ configuration.getDefaultJavacFlags(),
+ configuration.getDefaultJavaBuilderJvmFlags(),
+ headerCompiler);
RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext)
.add(JavaToolchainProvider.class, provider)
.setFilesToBuild(new NestedSetBuilder<Artifact>(Order.STABLE_ORDER).build())
@@ -51,4 +60,19 @@ public final class JavaToolchain implements RuleConfiguredTargetFactory {
return builder.build();
}
+
+ private Artifact getTurbine(RuleContext ruleContext) {
+ TransitiveInfoCollection prerequisite =
+ ruleContext.getPrerequisite("header_compiler", Mode.HOST);
+ if (prerequisite == null) {
+ return null;
+ }
+ Iterable<Artifact> artifacts = prerequisite.getProvider(FileProvider.class).getFilesToBuild();
+ if (Iterables.size(artifacts) != 1) {
+ ruleContext.attributeError(
+ "header_compiler", prerequisite.getLabel() + " expected a single artifact");
+ return null;
+ }
+ return Iterables.getOnlyElement(artifacts);
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
index e022538824..dca7ca15c4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainData.java
@@ -13,6 +13,8 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.java;
+import static com.google.devtools.build.lib.util.Preconditions.checkNotNull;
+
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
@@ -28,20 +30,24 @@ import java.util.List;
*/
@Immutable
public class JavaToolchainData {
-
+
private final String sourceVersion;
private final String targetVersion;
private final String encoding;
private final ImmutableList<String> options;
private final ImmutableList<String> jvmOpts;
- public JavaToolchainData(String sourceVersion, String targetVersion, String encoding,
- List<String> xlint, List<String> misc, List<String> jvmOpts) {
-
- this.sourceVersion = sourceVersion;
- this.targetVersion = targetVersion;
- this.encoding = encoding;
-
+ public JavaToolchainData(
+ String sourceVersion,
+ String targetVersion,
+ String encoding,
+ List<String> xlint,
+ List<String> misc,
+ List<String> jvmOpts) {
+ this.sourceVersion = checkNotNull(sourceVersion, "sourceVersion must not be null");
+ this.targetVersion = checkNotNull(targetVersion, "targetVersion must not be null");
+ this.encoding = checkNotNull(encoding, "encoding must not be null");
+
this.jvmOpts = ImmutableList.copyOf(jvmOpts);
Builder<String> builder = ImmutableList.<String>builder();
if (!sourceVersion.isEmpty()) {
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
index 6063896923..1457935c20 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainProvider.java
@@ -13,7 +13,10 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.java;
+import static com.google.devtools.build.lib.util.Preconditions.checkNotNull;
+
import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoProvider;
@@ -22,55 +25,16 @@ import com.google.devtools.build.lib.packages.BuildType;
import java.util.List;
+import javax.annotation.Nullable;
+
/**
* Information about the JDK used by the <code>java_*</code> rules.
*/
@Immutable
public final class JavaToolchainProvider implements TransitiveInfoProvider {
- private final String sourceVersion;
- private final String targetVersion;
- private final String encoding;
- private final ImmutableList<String> javacOptions;
- private final ImmutableList<String> javacJvmOptions;
-
- public JavaToolchainProvider(JavaToolchainData data, List<String> defaultJavacFlags,
- List<String> defaultJavacJvmOpts) {
-
- this.sourceVersion = data.getSourceVersion();
- this.targetVersion = data.getTargetVersion();
- this.encoding = data.getEncoding();
-
- // merges the defaultJavacFlags from
- // {@link JavaConfiguration} with the flags from the {@code java_toolchain} rule.
- this.javacOptions = ImmutableList.<String>builder()
- .addAll(data.getJavacOptions())
- .addAll(defaultJavacFlags)
- .build();
- // merges the defaultJavaBuilderJvmFlags from
- // {@link JavaConfiguration} with the flags from the {@code java_toolchain} rule.
- this.javacJvmOptions = ImmutableList.<String>builder()
- .addAll(data.getJavacJvmOptions())
- .addAll(defaultJavacJvmOpts)
- .build();
- }
-
/**
- * @return the list of default options for the java compiler
- */
- public ImmutableList<String> getJavacOptions() {
- return javacOptions;
- }
-
- /**
- * @return the list of default options for the JVM running the java compiler
- */
- public ImmutableList<String> getJavacJvmOptions() {
- return javacJvmOptions;
- }
-
- /**
- * An helper method to construct the list of javac options.
+ * Constructs the list of javac options.
*
* @param ruleContext The rule context of the current rule.
* @return the list of flags provided by the {@code java_toolchain} rule merged with the one
@@ -87,14 +51,14 @@ public final class JavaToolchainProvider implements TransitiveInfoProvider {
}
/**
- * An helper method to construct the list of options to pass to the JVM running the java compiler.
+ * Constructs the list of options to pass to the JVM running the java compiler.
*
* @param ruleContext The rule context of the current rule.
* @return the list of flags provided by the {@code java_toolchain} rule merged with the one
* provided by the {@link JavaConfiguration} fragment.
*/
public static List<String> getDefaultJavacJvmOptions(RuleContext ruleContext) {
- if (!ruleContext.getRule().isAttrDefined(":java_toolchain", BuildType.LABEL)) {
+ if (!ruleContext.getRule().isAttrDefined(":java_toolchain", BuildType.LABEL)) {
// As some rules might not have java_toolchain dependency (e.g., java_import), we silently
// ignore it. The rules needing it will error in #getDefaultJavacOptions(RuleContext) anyway.
return ImmutableList.of();
@@ -108,15 +72,77 @@ public final class JavaToolchainProvider implements TransitiveInfoProvider {
return javaToolchain.getJavacJvmOptions();
}
+ /** Returns the {@link Artifact} of the header compiler deploy jar. */
+ public static Artifact getHeaderCompilerJar(RuleContext ruleContext) {
+ JavaToolchainProvider javaToolchain =
+ ruleContext.getPrerequisite(":java_toolchain", Mode.TARGET, JavaToolchainProvider.class);
+ if (javaToolchain == null) {
+ ruleContext.ruleError("The --java_toolchain option does not point to a java_toolchain rule.");
+ return null;
+ }
+ return javaToolchain.getHeaderCompiler();
+ }
+
+ private final String sourceVersion;
+ private final String targetVersion;
+ private final String encoding;
+ private final ImmutableList<String> javacOptions;
+ private final ImmutableList<String> javacJvmOptions;
+ @Nullable private final Artifact headerCompiler;
+
+ public JavaToolchainProvider(
+ JavaToolchainData data,
+ List<String> defaultJavacFlags,
+ List<String> defaultJavacJvmOpts,
+ @Nullable Artifact headerCompiler) {
+ this.sourceVersion = checkNotNull(data.getSourceVersion(), "sourceVersion must not be null");
+ this.targetVersion = checkNotNull(data.getTargetVersion(), "targetVersion must not be null");
+ this.encoding = checkNotNull(data.getEncoding(), "encoding must not be null");
+ this.headerCompiler = headerCompiler;
+
+ // merges the defaultJavacFlags from
+ // {@link JavaConfiguration} with the flags from the {@code java_toolchain} rule.
+ this.javacOptions =
+ ImmutableList.<String>builder()
+ .addAll(data.getJavacOptions())
+ .addAll(defaultJavacFlags)
+ .build();
+ // merges the defaultJavaBuilderJvmFlags from
+ // {@link JavaConfiguration} with the flags from the {@code java_toolchain} rule.
+ this.javacJvmOptions =
+ ImmutableList.<String>builder()
+ .addAll(data.getJavacJvmOptions())
+ .addAll(defaultJavacJvmOpts)
+ .build();
+ }
+
+ /** @return the list of default options for the java compiler */
+ public ImmutableList<String> getJavacOptions() {
+ return javacOptions;
+ }
+
+ /** @return the list of default options for the JVM running the java compiler */
+ public ImmutableList<String> getJavacJvmOptions() {
+ return javacJvmOptions;
+ }
+
+ /** @return the input Java language level */
public String getSourceVersion() {
return sourceVersion;
}
+ /** @return the target Java language level */
public String getTargetVersion() {
return targetVersion;
}
+ /** @return the encoding for Java source files */
public String getEncoding() {
return encoding;
}
+
+ /** @return the {@link Artifact} of the Header Compiler deploy jar */
+ public Artifact getHeaderCompiler() {
+ return headerCompiler;
+ }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
index b79cfab469..d1c982c2fe 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaToolchainRule.java
@@ -13,7 +13,9 @@
// limitations under the License.
package com.google.devtools.build.lib.rules.java;
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
import static com.google.devtools.build.lib.syntax.Type.STRING;
import static com.google.devtools.build.lib.syntax.Type.STRING_LIST;
@@ -23,6 +25,7 @@ import com.google.devtools.build.lib.analysis.RuleDefinition;
import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
import com.google.devtools.build.lib.packages.RuleClass;
import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.util.FileTypeSet;
/**
* Rule definition for {@code java_toolchain}
@@ -30,7 +33,8 @@ import com.google.devtools.build.lib.packages.RuleClass.Builder;
public final class JavaToolchainRule implements RuleDefinition {
@Override
public RuleClass build(Builder builder, RuleDefinitionEnvironment env) {
- return builder.requiresConfigurationFragments(JavaConfiguration.class)
+ return builder
+ .requiresConfigurationFragments(JavaConfiguration.class)
/* <!-- #BLAZE_RULE(java_toolchain).ATTRIBUTE(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.
@@ -60,6 +64,7 @@ public final class JavaToolchainRule implements RuleDefinition {
virtual machine documentation for the extensive list of possible flags for this option.
<!-- #END_BLAZE_RULE.ATTRIBUTE --> */
.add(attr("jvm_opts", STRING_LIST).value(ImmutableList.<String>of("-client")))
+ .add(attr("header_compiler", LABEL).cfg(HOST).allowedFileTypes(FileTypeSet.ANY_FILE).exec())
.build();
}
diff --git a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
index 700fa604b3..8b5817ffda 100644
--- a/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
+++ b/src/test/java/com/google/devtools/build/lib/analysis/mock/BazelAnalysisMock.java
@@ -90,7 +90,8 @@ public final class BazelAnalysisMock extends AnalysisMock {
// "dummy" is needed so that RedirectChaser stops here
"filegroup(name='java', srcs = ['jdk/jre/bin/java', 'dummy'])",
"exports_files(['JavaBuilder_deploy.jar','SingleJar_deploy.jar','TestRunner_deploy.jar',",
- " 'JavaBuilderCanary_deploy.jar', 'ijar', 'GenClass_deploy.jar'])");
+ " 'JavaBuilderCanary_deploy.jar', 'ijar', 'GenClass_deploy.jar',",
+ " 'turbine_deploy.jar'])");
ImmutableList<String> androidBuildContents = createAndroidBuildContents();