diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build')
11 files changed, 549 insertions, 70 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(); } |