aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2016-01-15 23:40:14 +0000
committerGravatar Han-Wen Nienhuys <hanwen@google.com>2016-01-18 14:32:16 +0000
commite3ce21fab041c6c8e6da2811f5dce75615ccb1f4 (patch)
tree810872c48d6b59f8b7cc3de6dbe5cfb4c0bfbb87 /src/main
parent4a24477ce0fa3249160cc61b455db3ad6e247a43 (diff)
support hidden --java_optimization_mode flag in java_test rule.
-- MOS_MIGRATED_REVID=112290581
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java6
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java27
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java19
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java22
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java3
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java114
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java17
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java8
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java16
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java (renamed from src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java)143
10 files changed, 282 insertions, 93 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
index c3c5b7558c..82c0012a60 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/java/BazelJavaTestRule.java
@@ -14,8 +14,10 @@
package com.google.devtools.build.lib.bazel.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.packages.BuildType.LABEL_LIST;
import static com.google.devtools.build.lib.packages.BuildType.TRISTATE;
import static com.google.devtools.build.lib.syntax.Type.BOOLEAN;
import static com.google.devtools.build.lib.syntax.Type.STRING;
@@ -51,6 +53,10 @@ public final class BazelJavaTestRule implements RuleDefinition {
return builder
.requiresConfigurationFragments(JavaConfiguration.class, Jvm.class)
.setImplicitOutputsFunction(BazelJavaRuleClasses.JAVA_BINARY_IMPLICIT_OUTPUTS)
+ // Proguard can be run over java_test targets using the --java_optimization_mode flag.
+ // Primarily this is intended to help test changes to Proguard.
+ .add(attr(":proguard", LABEL).cfg(HOST).value(JavaSemantics.PROGUARD).exec())
+ .add(attr(":extra_proguard_specs", LABEL_LIST).value(JavaSemantics.EXTRA_PROGUARD_SPECS))
.override(attr("stamp", TRISTATE).value(TriState.NO))
.override(attr("use_testrunner", BOOLEAN).value(true))
.override(attr(":java_launcher", LABEL).value(JavaSemantics.JAVA_LAUNCHER))
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
index de84cec192..2979e4e0db 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidBinary.java
@@ -14,7 +14,6 @@
package com.google.devtools.build.lib.rules.android;
import static com.google.common.base.Strings.isNullOrEmpty;
-import static com.google.devtools.build.lib.rules.android.ProguardHelper.PROGUARD_SPECS;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableList;
@@ -48,7 +47,6 @@ import com.google.devtools.build.lib.packages.BuildType;
import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory;
import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode;
-import com.google.devtools.build.lib.rules.android.ProguardHelper.ProguardOutput;
import com.google.devtools.build.lib.rules.cpp.CcToolchainProvider;
import com.google.devtools.build.lib.rules.cpp.CppHelper;
import com.google.devtools.build.lib.rules.java.DeployArchiveBuilder;
@@ -59,6 +57,8 @@ import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizati
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.rules.java.ProguardHelper;
+import com.google.devtools.build.lib.rules.java.ProguardHelper.ProguardOutput;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
@@ -131,7 +131,9 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
}
if (ruleContext.attributes().isAttributeValueExplicitlySpecified("proguard_apply_mapping")
- && ruleContext.attributes().get(PROGUARD_SPECS, BuildType.LABEL_LIST).isEmpty()) {
+ && ruleContext.attributes()
+ .get(ProguardHelper.PROGUARD_SPECS, BuildType.LABEL_LIST)
+ .isEmpty()) {
ruleContext.attributeError("proguard_apply_mapping",
"'proguard_apply_mapping' can only be used when 'proguard_specs' is also set");
return null;
@@ -342,7 +344,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ImmutableList<Artifact> apksUnderTest,
Artifact proguardMapping) throws InterruptedException {
ImmutableList<Artifact> proguardSpecs = ProguardHelper.collectTransitiveProguardSpecs(
- ruleContext, resourceApk.getResourceProguardConfig());
+ ruleContext, ImmutableList.of(resourceApk.getResourceProguardConfig()));
ProguardOutput proguardOutput =
applyProguard(
@@ -731,7 +733,10 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.getJavaOptimizationMode();
}
- /** Applies the proguard specifications, and creates a ProguardedJar. */
+ /**
+ * Applies the proguard specifications, and creates a ProguardedJar. Proguard's output artifacts
+ * are added to the given {@code filesBuilder}.
+ */
private static ProguardOutput applyProguard(
RuleContext ruleContext,
AndroidCommon common,
@@ -757,9 +762,12 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
.add(sdk.getAndroidJar())
.addTransitive(common.getTransitiveNeverLinkLibraries())
.build();
- return ProguardHelper.createProguardAction(ruleContext, sdk.getProguard(), deployJarArtifact,
- proguardSpecs, proguardMapping, libraryJars, proguardOutputJar,
- ruleContext.attributes().get("proguard_generate_mapping", Type.BOOLEAN), filesBuilder);
+ ProguardOutput result = ProguardHelper.createProguardAction(ruleContext, sdk.getProguard(),
+ deployJarArtifact, proguardSpecs, proguardMapping, libraryJars, proguardOutputJar,
+ ruleContext.attributes().get("proguard_generate_mapping", Type.BOOLEAN));
+ // Since Proguard is being run, add its output artifacts to the given filesBuilder
+ result.addAllToSet(filesBuilder);
+ return result;
}
private static ProguardOutput createEmptyProguardAction(RuleContext ruleContext,
@@ -767,8 +775,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory {
ImmutableList.Builder<Artifact> failures =
ImmutableList.<Artifact>builder().add(proguardOutputJar);
if (ruleContext.attributes().get("proguard_generate_mapping", Type.BOOLEAN)) {
- failures.add(
- ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_MAP));
+ failures.add(ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_MAP));
}
JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext);
ruleContext.registerAction(
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
index 05f5e2ceb5..564a344325 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidConfiguration.java
@@ -21,7 +21,6 @@ import com.google.devtools.build.lib.Constants;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.DefaultLabelConverter;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.Fragment;
-import com.google.devtools.build.lib.analysis.config.BuildConfiguration.LabelConverter;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsConverter;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
@@ -146,14 +145,6 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
help = "Specifies Android SDK/platform that is used to build Android applications.")
public Label sdk;
- @Option(name = "proguard_top",
- defaultValue = "null",
- category = "version",
- converter = LabelConverter.class,
- help = "Specifies which version of ProGuard to use for code removal when building an "
- + "Android binary.")
- public Label proguard;
-
@Option(name = "legacy_android_native_support",
defaultValue = "true",
category = "semantics",
@@ -188,10 +179,6 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
@Override
public void addAllLabels(Multimap<String, Label> labelMap) {
- if (proguard != null) {
- labelMap.put("android_proguard", proguard);
- }
-
if (androidCrosstoolTop != null) {
labelMap.put("android_crosstool_top", androidCrosstoolTop);
}
@@ -249,7 +236,6 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
private final boolean incrementalNativeLibs;
private final boolean fatApk;
private final ConfigurationDistinguisher configurationDistinguisher;
- private final Label proguard;
private final boolean useJackForDexing;
private final boolean jackSanityChecks;
@@ -261,7 +247,6 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
this.cpu = options.cpu;
this.fatApk = !options.realFatApkCpus().isEmpty();
this.configurationDistinguisher = options.configurationDistinguisher;
- this.proguard = options.proguard;
this.useJackForDexing = options.useJackForDexing;
this.jackSanityChecks = options.jackSanityChecks;
}
@@ -314,8 +299,4 @@ public class AndroidConfiguration extends BuildConfiguration.Fragment {
public String getOutputDirectoryName() {
return configurationDistinguisher.suffix;
}
-
- public Label getProguardLabel() {
- return proguard;
- }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
index 09702fcf93..f4704d329b 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidRuleClasses.java
@@ -47,6 +47,7 @@ import com.google.devtools.build.lib.packages.TriState;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.ConfigurationDistinguisher;
import com.google.devtools.build.lib.rules.cpp.CppOptions;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.FileType;
@@ -92,8 +93,6 @@ public final class AndroidRuleClasses {
fromTemplates("%{name}_deploy.jar");
public static final SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_JAR =
fromTemplates("%{name}_proguard.jar");
- public static final SafeImplicitOutputsFunction ANDROID_BINARY_PROGUARD_MAP =
- fromTemplates("%{name}_proguard.map");
public static final SafeImplicitOutputsFunction ANDROID_BINARY_INSTRUMENTED_JAR =
fromTemplates("%{name}_instrumented.jar");
public static final SafeImplicitOutputsFunction ANDROID_TEST_FILTERED_JAR =
@@ -150,19 +149,6 @@ public final class AndroidRuleClasses {
public static final Label DEFAULT_AAR_GENERATOR =
Label.parseAbsoluteUnchecked(Constants.TOOLS_REPOSITORY + "//tools/android:aar_generator");
- /**
- * Implementation for the :proguard attribute.
- */
- static final LateBoundLabel<BuildConfiguration> PROGUARD =
- new LateBoundLabel<BuildConfiguration>(AndroidConfiguration.class) {
- @Override
- public Label getDefault(Rule rule, BuildConfiguration configuration) {
- // If --proguard_top is not specified, null is returned. AndroidSdk will take care of using
- // android_sdk.proguard then.
- return configuration.getFragment(AndroidConfiguration.class).getProguardLabel();
- }
- };
-
public static final LateBoundLabel<BuildConfiguration> ANDROID_SDK =
new LateBoundLabel<BuildConfiguration>(DEFAULT_ANDROID_SDK, AndroidConfiguration.class) {
@Override
@@ -276,7 +262,7 @@ public final class AndroidRuleClasses {
if (hasProguardSpecs) {
functions.add(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_JAR);
if (mapping) {
- functions.add(AndroidRuleClasses.ANDROID_BINARY_PROGUARD_MAP);
+ functions.add(JavaSemantics.JAVA_BINARY_PROGUARD_MAP);
}
}
return fromFunctions(functions).getImplicitOutputs(rule);
@@ -315,10 +301,10 @@ public final class AndroidRuleClasses {
@Override
public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
return builder
- .requiresConfigurationFragments(AndroidConfiguration.class)
+ .requiresConfigurationFragments(JavaConfiguration.class, AndroidConfiguration.class)
.setUndocumented()
// This is the Proguard that comes from the --proguard_top attribute.
- .add(attr(":proguard", LABEL).cfg(HOST).value(PROGUARD).exec())
+ .add(attr(":proguard", LABEL).cfg(HOST).value(JavaSemantics.PROGUARD).exec())
// This is the Proguard in the BUILD file that contains the android_sdk rule. Used when
// --proguard_top is not specified.
.add(attr("proguard", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE).exec())
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
index f00b415aae..8904b22e68 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdk.java
@@ -23,6 +23,7 @@ import com.google.devtools.build.lib.analysis.RunfilesProvider;
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;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
/**
* Implementation of the {@code android_sdk} rule.
@@ -33,7 +34,7 @@ public class AndroidSdk implements RuleConfiguredTargetFactory {
// If the user didn't specify --proguard_top, go with the proguard attribute in the android_sdk
// rule. Otherwise, use what she told us to.
FilesToRunProvider proguard =
- ruleContext.getFragment(AndroidConfiguration.class).getProguardLabel() == null
+ ruleContext.getFragment(JavaConfiguration.class).getProguardBinary() == null
? ruleContext.getExecutablePrerequisite("proguard", Mode.HOST)
: ruleContext.getExecutablePrerequisite(":proguard", Mode.HOST);
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
index 87d45b9c92..67ba2c3dff 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaBinary.java
@@ -14,6 +14,7 @@
package com.google.devtools.build.lib.rules.java;
import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.COMPRESSED;
+import static com.google.devtools.build.lib.rules.java.DeployArchiveBuilder.Compression.UNCOMPRESSED;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -22,6 +23,7 @@ import com.google.common.collect.Lists;
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.FilesToRunProvider;
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;
@@ -46,6 +48,8 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
+import javax.annotation.Nullable;
+
/**
* An implementation of java_binary.
*/
@@ -213,21 +217,45 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
RuleConfiguredTargetBuilder builder =
new RuleConfiguredTargetBuilder(ruleContext);
- semantics.addProviders(ruleContext, common, jvmFlags, classJar, srcJar,
- genClassJar, genSourceJar, ImmutableMap.<Artifact, Artifact>of(),
+ semantics.addProviders(ruleContext, common, jvmFlags, classJar, srcJar,
+ genClassJar, genSourceJar, ImmutableMap.<Artifact, Artifact>of(),
helper, filesBuilder, builder);
+ Artifact deployJar =
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_JAR);
+ boolean runProguard = applyProguardIfRequested(
+ ruleContext, deployJar, common.getBootClasspath(), mainClass, filesBuilder);
+
NestedSet<Artifact> filesToBuild = filesBuilder.build();
+ // Need not include normal runtime classpath in runfiles if Proguard is used because _deploy.jar
+ // is used as classpath instead. Keeping runfiles unchanged has however the advantage that
+ // manually running executable without --singlejar works (although it won't depend on Proguard).
collectDefaultRunfiles(runfilesBuilder, ruleContext, common, filesToBuild, launcher,
dynamicRuntimeActionInputs);
Runfiles defaultRunfiles = runfilesBuilder.build();
- RunfilesSupport runfilesSupport = createExecutable
- ? runfilesSupport = RunfilesSupport.withExecutable(
- ruleContext, defaultRunfiles, executable,
- semantics.getExtraArguments(ruleContext, common))
- : null;
+ RunfilesSupport runfilesSupport = null;
+ if (createExecutable) {
+ List<String> extraArgs = new ArrayList<>(semantics.getExtraArguments(ruleContext, common));
+ if (runProguard) {
+ // Instead of changing the classpath written into the wrapper script, pass --singlejar when
+ // running the script (which causes the deploy.jar written by Proguard to be used instead of
+ // the normal classpath). It's a bit odd to do this b/c manually running the script wouldn't
+ // use Proguard's output unless --singlejar is explicitly supplied. On the other hand the
+ // behavior of the script is more consistent: the (proguarded) deploy.jar is only used with
+ // --singlejar. Moreover, people will almost always run tests using blaze test, which does
+ // use Proguard's output thanks to this extra arg when enabled. Also, it's actually hard to
+ // get the classpath changed in the wrapper script (would require calling
+ // JavaCommon.setClasspathFragment with a new fragment at the *end* of this method because
+ // the classpath is evaluated lazily when generating the wrapper script) and the wrapper
+ // script would essentially have an if (--singlejar was set), set classpath to deploy jar,
+ // otherwise, set classpath to deploy jar.
+ extraArgs.add("--wrapper_script_flag=--singlejar");
+ }
+ runfilesSupport =
+ RunfilesSupport.withExecutable(ruleContext, defaultRunfiles, executable, extraArgs);
+ }
RunfilesProvider runfilesProvider = RunfilesProvider.withData(
defaultRunfiles,
@@ -236,26 +264,30 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
ImmutableList<String> deployManifestLines =
getDeployManifestLines(ruleContext, originalMainClass);
- Artifact deployJar =
- ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_DEPLOY_JAR);
-
- Artifact unstrippedDeployJar =
- ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR);
-
+ // When running Proguard:
+ // (1) write single jar to intermediate destination; Proguard will write _deploy.jar file
+ // (2) Don't depend on runfiles to avoid circular dependency, since _deploy.jar is itself part
+ // of runfiles when Proguard runs (because executable then needs it) and _deploy.jar depends
+ // on this single jar.
+ // (3) Don't bother with compression since Proguard will write the final jar anyways
deployArchiveBuilder
- .setOutputJar(deployJar)
+ .setOutputJar(
+ runProguard
+ ? ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_MERGED_JAR)
+ : deployJar)
.setJavaStartClass(mainClass)
.setDeployManifestLines(deployManifestLines)
.setAttributes(attributes)
.addRuntimeJars(common.getJavaCompilationArtifacts().getRuntimeJars())
.setIncludeBuildData(true)
.setRunfilesMiddleman(
- runfilesSupport == null ? null : runfilesSupport.getRunfilesMiddleman())
- .setCompression(COMPRESSED)
- .setLauncher(launcher);
-
- deployArchiveBuilder.build();
+ runProguard || runfilesSupport == null ? null : runfilesSupport.getRunfilesMiddleman())
+ .setCompression(runProguard ? UNCOMPRESSED : COMPRESSED)
+ .setLauncher(launcher)
+ .build();
+ Artifact unstrippedDeployJar =
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR);
if (stripAsDefault) {
unstrippedDeployArchiveBuilder
.setOutputJar(unstrippedDeployJar)
@@ -413,4 +445,48 @@ public class JavaBinary implements RuleConfiguredTargetFactory {
return result.build();
}
+
+ /**
+ * This method uses {@link ProguardHelper#applyProguardIfRequested} to create a proguard action
+ * if necessary and adds any artifacts created by proguard to the given {@code filesBuilder}.
+ * This is convenience to make sure the proguarded Jar is included in the files to build, which is
+ * necessary because the Jar written by proguard is used at runtime.
+ * If this method returns {@code true} the Proguard is being used and we need to use a
+ * {@link DeployArchiveBuilder} to write the input artifact assumed by
+ * {@link ProguardHelper#applyProguardIfRequested}.
+ */
+ private static boolean applyProguardIfRequested(RuleContext ruleContext, Artifact deployJar,
+ ImmutableList<Artifact> bootclasspath, String mainClassName,
+ NestedSetBuilder<Artifact> filesBuilder) throws InterruptedException {
+ // We only support proguarding tests so Proguard doesn't try to proguard itself.
+ if (!ruleContext.getRule().getRuleClass().endsWith("_test")) {
+ return false;
+ }
+ ProguardHelper.ProguardOutput output =
+ JavaBinaryProguardHelper.INSTANCE.applyProguardIfRequested(
+ ruleContext, deployJar, bootclasspath, mainClassName);
+ if (output == null) {
+ return false;
+ }
+ output.addAllToSet(filesBuilder);
+ return true;
+ }
+
+ private static class JavaBinaryProguardHelper extends ProguardHelper {
+
+ static final JavaBinaryProguardHelper INSTANCE = new JavaBinaryProguardHelper();
+
+ @Override
+ @Nullable
+ protected FilesToRunProvider findProguard(RuleContext ruleContext) {
+ // TODO(bazel-team): Find a way to use Proguard specified in android_sdk rules
+ return ruleContext.getExecutablePrerequisite(":proguard", Mode.HOST);
+ }
+
+ @Override
+ protected ImmutableList<Artifact> collectProguardSpecsForRule(RuleContext ruleContext,
+ String mainClassName) {
+ return ImmutableList.of(generateSpecForJavaBinary(ruleContext, mainClassName));
+ }
+ }
}
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 315cf67797..2983140fd0 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
@@ -32,6 +32,8 @@ import com.google.devtools.common.options.TriState;
import java.util.List;
+import javax.annotation.Nullable;
+
/**
* A java compiler configuration containing the flags required for compilation.
*/
@@ -137,17 +139,17 @@ public final class JavaConfiguration extends Fragment {
private final Label javacBootclasspath;
private final Label javacExtdir;
private final ImmutableList<String> javacOpts;
+ private final Label proguardBinary;
private final ImmutableList<Label> extraProguardSpecs;
private final TriState bundleTranslations;
private final ImmutableList<Label> translationTargets;
private final String javaCpu;
private final JavaOptimizationMode javaOptimizationMode;
-
private final Label javaToolchain;
// TODO(dmarting): remove when we have rolled out the new behavior
private final boolean legacyBazelJavaTest;
-
+
JavaConfiguration(boolean generateJavaDeps,
List<String> defaultJvmFlags, JavaOptions javaOptions, Label javaToolchain, String javaCpu,
ImmutableList<String> defaultJavaBuilderJvmOpts)
@@ -168,6 +170,7 @@ public final class JavaConfiguration extends Fragment {
this.javacBootclasspath = javaOptions.javacBootclasspath;
this.javacExtdir = javaOptions.javacExtdir;
this.javacOpts = ImmutableList.copyOf(javaOptions.javacOpts);
+ this.proguardBinary = javaOptions.proguard;
this.extraProguardSpecs = ImmutableList.copyOf(javaOptions.extraProguardSpecs);
this.bundleTranslations = javaOptions.bundleTranslations;
this.javaCpu = javaCpu;
@@ -299,6 +302,14 @@ public final class JavaConfiguration extends Fragment {
}
/**
+ * Returns the label provided with --proguard_top, if any.
+ */
+ @Nullable
+ public Label getProguardBinary() {
+ return proguardBinary;
+ }
+
+ /**
* Returns all labels provided with --extra_proguard_specs.
*/
public List<Label> getExtraProguardSpecs() {
@@ -341,7 +352,7 @@ public final class JavaConfiguration extends Fragment {
public JavaOptimizationMode getJavaOptimizationMode() {
return javaOptimizationMode;
}
-
+
/**
* Returns true if java_test in Bazel should behave in legacy mode that existed before we
* open-sourced our test runner.
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 2a091cacc9..0a5fcc0455 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
@@ -346,6 +346,14 @@ public class JavaOptions extends FragmentOptions {
+ "The \"launcher\" attribute overrides this flag. ")
public Label javaLauncher;
+ @Option(name = "proguard_top",
+ defaultValue = "null",
+ category = "version",
+ converter = LabelConverter.class,
+ help = "Specifies which version of ProGuard to use for code removal when building a Java "
+ + "binary.")
+ public Label proguard;
+
@Option(name = "extra_proguard_specs",
allowMultiple = true,
defaultValue = "", // Ignored
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
index 741228b4c4..b502cdcc1f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaSemantics.java
@@ -62,9 +62,12 @@ public interface JavaSemantics {
SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_JAR =
fromTemplates("%{name}_deploy.jar");
-
+ SafeImplicitOutputsFunction JAVA_BINARY_MERGED_JAR =
+ fromTemplates("%{name}_merged.jar");
SafeImplicitOutputsFunction JAVA_UNSTRIPPED_BINARY_DEPLOY_JAR =
fromTemplates("%{name}_deploy.jar.unstripped");
+ SafeImplicitOutputsFunction JAVA_BINARY_PROGUARD_MAP =
+ fromTemplates("%{name}_proguard.map");
SafeImplicitOutputsFunction JAVA_BINARY_DEPLOY_SOURCE_JAR =
fromTemplates("%{name}_deploy-src.jar");
@@ -182,6 +185,17 @@ public interface JavaSemantics {
}
};
+ /**
+ * Implementation for the :proguard attribute.
+ */
+ LateBoundLabel<BuildConfiguration> PROGUARD =
+ new LateBoundLabel<BuildConfiguration>(JavaConfiguration.class) {
+ @Override
+ public Label getDefault(Rule rule, BuildConfiguration configuration) {
+ return configuration.getFragment(JavaConfiguration.class).getProguardBinary();
+ }
+ };
+
LateBoundLabelList<BuildConfiguration> EXTRA_PROGUARD_SPECS =
new LateBoundLabelList<BuildConfiguration>() {
@Override
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java
index f752e182a5..98e01d1f09 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java
@@ -11,7 +11,10 @@
// 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.android;
+package com.google.devtools.build.lib.rules.java;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.devtools.build.lib.collect.nestedset.Order.NAIVE_LINK_ORDER;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
@@ -28,26 +31,30 @@ import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.packages.BuildType;
-import com.google.devtools.build.lib.rules.java.JavaConfiguration;
import com.google.devtools.build.lib.rules.java.JavaConfiguration.JavaOptimizationMode;
-import com.google.devtools.build.lib.rules.java.ProguardSpecProvider;
import javax.annotation.Nullable;
/**
- * Common code for proguarding Android binaries.
+ * Common code for proguarding Java binaries.
*/
-public class ProguardHelper {
+public abstract class ProguardHelper {
- static final String PROGUARD_SPECS = "proguard_specs";
+ /**
+ * Attribute for attaching proguard specs explicitly to a rule, if such an attribute is desired.
+ */
+ public static final String PROGUARD_SPECS = "proguard_specs";
+ /**
+ * Pair summarizing Proguard's output: a Jar file and an optional obfuscation mapping file.
+ */
@Immutable
- static final class ProguardOutput {
+ public static final class ProguardOutput {
private final Artifact outputJar;
@Nullable private final Artifact mapping;
- ProguardOutput(Artifact outputJar, @Nullable Artifact mapping) {
- this.outputJar = outputJar;
+ public ProguardOutput(Artifact outputJar, @Nullable Artifact mapping) {
+ this.outputJar = checkNotNull(outputJar);
this.mapping = mapping;
}
@@ -60,9 +67,76 @@ public class ProguardHelper {
return mapping;
}
+ /** Adds the output artifacts to the given set builder. */
+ public void addAllToSet(NestedSetBuilder<Artifact> filesBuilder) {
+ filesBuilder.add(outputJar);
+ if (mapping != null) {
+ filesBuilder.add(mapping);
+ }
+ }
+ }
+
+ protected ProguardHelper() {}
+
+ /**
+ * Creates an action to run Proguard to <i>output</i> the given {@code deployJar} artifact
+ * if --java_optimization_mode calls for it from an assumed input artifact
+ * {@link JavaSemantics#JAVA_BINARY_MERGED_JAR}. Returns the artifacts that Proguard will
+ * generate or {@code null} if Proguard isn't used.
+ *
+ * <p>If this method returns artifacts then {@link DeployArchiveBuilder} needs to write the
+ * assumed input artifact (instead of the conventional deploy.jar, which now Proguard writes).
+ * Do not use this method for binary rules that themselves declare {@link #PROGUARD_SPECS}
+ * attributes, which includes of 1/2016 {@code android_binary} and {@code android_test}.
+ */
+ @Nullable
+ public ProguardOutput applyProguardIfRequested(RuleContext ruleContext, Artifact deployJar,
+ ImmutableList<Artifact> bootclasspath, String mainClassName) throws InterruptedException {
+ JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext);
+ if (optMode == JavaOptimizationMode.NOOP || optMode == JavaOptimizationMode.LEGACY) {
+ // For simplicity do nothing in LEGACY mode
+ return null;
+ }
+
+ Preconditions.checkArgument(bootclasspath.isEmpty(),
+ "Bootclasspath should be empty b/c not compiling for Android device: %s", bootclasspath);
+ FilesToRunProvider proguard = findProguard(ruleContext);
+ if (proguard == null) {
+ ruleContext.ruleError("--proguard_top required for --java_optimization_mode=" + optMode);
+ return null;
+ }
+
+ ImmutableList<Artifact> proguardSpecs = collectProguardSpecs(ruleContext, mainClassName);
+ Artifact singleJar =
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_MERGED_JAR);
+ return createProguardAction(ruleContext, proguard, singleJar, proguardSpecs, (Artifact) null,
+ NestedSetBuilder.<Artifact>emptySet(NAIVE_LINK_ORDER), deployJar,
+ /* mappingRequested */ false);
+ }
+
+ private ImmutableList<Artifact> collectProguardSpecs(
+ RuleContext ruleContext, String mainClassName) {
+ return ProguardHelper.collectTransitiveProguardSpecs(ruleContext,
+ collectProguardSpecsForRule(ruleContext, mainClassName));
}
- private ProguardHelper() {}
+ /**
+ * Returns the Proguard binary to invoke when using {@link #applyProguardIfRequested}. Returning
+ * {@code null} from this method will generate an error in that method.
+ *
+ * @return Proguard binary or {@code null} if none is available
+ */
+ @Nullable
+ protected abstract FilesToRunProvider findProguard(RuleContext ruleContext);
+
+ /**
+ * Returns rule-specific proguard specs not captured by {@link #PROGUARD_SPECS} attributes when
+ * using {@link #applyProguardIfRequested}. Typically these are generated artifacts such as specs
+ * generated for android resources. This method is only called if Proguard will definitely used,
+ * so it's ok to generate files here.
+ */
+ protected abstract ImmutableList<Artifact> collectProguardSpecsForRule(
+ RuleContext ruleContext, String mainClassName);
/**
* Retrieves the full set of proguard specs that should be applied to this binary, including the
@@ -72,10 +146,12 @@ public class ProguardHelper {
*
* <p>If Proguard shouldn't be applied, or the legacy link mode is used and there are no
* proguard_specs on this rule, an empty list will be returned, regardless of any given specs or
- * specs from dependencies. {@link AndroidBinary#createAndroidBinary} relies on that behavior.
+ * specs from dependencies.
+ * {@link com.google.devtools.build.lib.rules.android.AndroidBinary#createAndroidBinary} relies on
+ * that behavior.
*/
public static ImmutableList<Artifact> collectTransitiveProguardSpecs(RuleContext ruleContext,
- Artifact... specsToInclude) {
+ Iterable<Artifact> specsToInclude) {
JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext);
if (optMode == JavaOptimizationMode.NOOP) {
return ImmutableList.of();
@@ -94,7 +170,7 @@ public class ProguardHelper {
ImmutableSortedSet.Builder<Artifact> builder =
ImmutableSortedSet.orderedBy(Artifact.EXEC_PATH_COMPARATOR)
.addAll(proguardSpecs)
- .add(specsToInclude)
+ .addAll(specsToInclude)
.addAll(ruleContext
.getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET)
.list());
@@ -120,6 +196,31 @@ public class ProguardHelper {
}
/**
+ * Creates a proguard spec that tells proguard to use the JDK's rt.jar as a library jar, similar
+ * to how android_binary would give Android SDK's android.jar to Proguard as library jar, and
+ * to keep the binary's entry point, ie., the main() method to be invoked.
+ */
+ protected static Artifact generateSpecForJavaBinary(RuleContext ruleContext,
+ String mainClassName) {
+ // Add -libraryjars <java.home>/lib/rt.jar so Proguard uses JDK bootclasspath, which JavaCommon
+ // doesn't expose when building for JDK (see checkArgument in applyProguardIfRequested).
+ // Note <java.home>/lib/rt.jar refers to rt.jar that comes with JVM running Proguard, which
+ // should be identical to the JVM that will run the binary.
+ Artifact result = ProguardHelper.getProguardConfigArtifact(ruleContext, "jvm");
+ ruleContext.registerAction(
+ new FileWriteAction(
+ ruleContext.getActionOwner(),
+ result,
+ String.format("-libraryjars <java.home>/lib/rt.jar%n"
+ + "-keep class %s {%n"
+ + " public static void main(java.lang.String[]);%n"
+ + "}",
+ mainClassName),
+ /*executable*/ false));
+ return result;
+ }
+
+ /**
* Creates an action to run Proguard over the given {@code programJar} with various other given
* inputs to produce {@code proguardOutputJar}. If requested explicitly, or implicitly with
* --java_optimization_mode, the action also produces a mapping file (which shows what methods and
@@ -134,7 +235,6 @@ public class ProguardHelper {
* @param libraryJars any other Jar files that the {@code programJar} will run against
* @param mappingRequested whether to ask Proguard to output a mapping file (a mapping will be
* produced anyway if --java_optimization_mode includes obfuscation)
- * @param filesBuilder all artifacts produced by this rule will be added to this builder
*/
public static ProguardOutput createProguardAction(RuleContext ruleContext,
FilesToRunProvider proguard,
@@ -143,8 +243,7 @@ public class ProguardHelper {
@Nullable Artifact proguardMapping,
NestedSet<Artifact> libraryJars,
Artifact proguardOutputJar,
- boolean mappingRequested,
- NestedSetBuilder<Artifact> filesBuilder) throws InterruptedException {
+ boolean mappingRequested) throws InterruptedException {
JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext);
Preconditions.checkArgument(optMode != JavaOptimizationMode.NOOP);
Preconditions.checkArgument(optMode != JavaOptimizationMode.LEGACY || !proguardSpecs.isEmpty());
@@ -165,8 +264,6 @@ public class ProguardHelper {
.addArgument(libraryJar.getExecPathString());
}
- filesBuilder.add(proguardOutputJar);
-
if (proguardMapping != null) {
builder.addInput(proguardMapping)
.addArgument("-applymapping")
@@ -184,13 +281,12 @@ public class ProguardHelper {
if (mappingRequested || optMode.alwaysGenerateOutputMapping()) {
// TODO(bazel-team): Verify that proguard spec files don't contain -printmapping directions
// which this -printmapping command line flag will override.
- proguardOutputMap = ruleContext.getImplicitOutputArtifact(
- AndroidRuleClasses.ANDROID_BINARY_PROGUARD_MAP);
+ proguardOutputMap =
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_PROGUARD_MAP);
builder.addOutput(proguardOutputMap)
.addArgument("-printmapping")
.addArgument(proguardOutputMap.getExecPathString());
- filesBuilder.add(proguardOutputMap);
}
ruleContext.registerAction(builder.build(ruleContext));
@@ -209,7 +305,10 @@ public class ProguardHelper {
ruleContext.getBinOrGenfilesDirectory()));
}
- private static JavaOptimizationMode getJavaOptimizationMode(RuleContext ruleContext) {
+ /**
+ * Returns {@link JavaConfiguration#getJavaOptimizationMode()}.
+ */
+ public static JavaOptimizationMode getJavaOptimizationMode(RuleContext ruleContext) {
return ruleContext.getConfiguration().getFragment(JavaConfiguration.class)
.getJavaOptimizationMode();
}