diff options
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java | 320 |
1 files changed, 170 insertions, 150 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java index 8886997892..c046985658 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/java/ProguardHelper.java @@ -27,9 +27,9 @@ import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode; import com.google.devtools.build.lib.analysis.RuleContext; import com.google.devtools.build.lib.analysis.TransitiveInfoCollection; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; import com.google.devtools.build.lib.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; -import com.google.devtools.build.lib.analysis.actions.SpawnAction.Builder; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; @@ -40,9 +40,7 @@ import com.google.devtools.build.lib.syntax.Type; import java.util.Map; import javax.annotation.Nullable; -/** - * Common code for proguarding Java binaries. - */ +/** Common code for proguarding Java binaries. */ public abstract class ProguardHelper { /** @@ -50,9 +48,7 @@ public abstract class ProguardHelper { */ public static final String PROGUARD_SPECS = "proguard_specs"; - /** - * A class collecting Proguard output artifacts. - */ + /** A class collecting Proguard output artifacts. */ @Immutable public static final class ProguardOutput { private final Artifact outputJar; @@ -63,13 +59,14 @@ public abstract class ProguardHelper { @Nullable private final Artifact constantStringObfuscatedMapping; private final Artifact config; - public ProguardOutput(Artifact outputJar, - @Nullable Artifact mapping, - @Nullable Artifact protoMapping, - @Nullable Artifact seeds, - @Nullable Artifact usage, - @Nullable Artifact constantStringObfuscatedMapping, - Artifact config) { + public ProguardOutput( + Artifact outputJar, + @Nullable Artifact mapping, + @Nullable Artifact protoMapping, + @Nullable Artifact seeds, + @Nullable Artifact usage, + @Nullable Artifact constantStringObfuscatedMapping, + Artifact config) { this.outputJar = checkNotNull(outputJar); this.mapping = mapping; this.protoMapping = protoMapping; @@ -117,8 +114,10 @@ public abstract class ProguardHelper { addAllToSet(filesBuilder, null); } - /** Adds the output artifacts to the given set builder. If the progaurd map was updated - * then add the updated map instead of the original proguard output map */ + /** + * Adds the output artifacts to the given set builder. If the progaurd map was updated then add + * the updated map instead of the original proguard output map + */ public void addAllToSet(NestedSetBuilder<Artifact> filesBuilder, Artifact finalProguardMap) { filesBuilder.add(outputJar); if (protoMapping != null) { @@ -213,7 +212,7 @@ public abstract class ProguardHelper { } /** - * Returns the Proguard binary to invoke when using {@link #applyProguardIfRequested}. Returning + * 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 @@ -223,7 +222,7 @@ public abstract class ProguardHelper { /** * Returns rule-specific proguard specs not captured by {@link #PROGUARD_SPECS} attributes when - * using {@link #applyProguardIfRequested}. Typically these are generated artifacts such as specs + * 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. */ @@ -232,18 +231,18 @@ public abstract class ProguardHelper { /** * Retrieves the full set of proguard specs that should be applied to this binary, including the - * specs passed in, if Proguard should run on the given rule. {@link #createProguardAction} - * relies on this method returning an empty list if the given rule doesn't declare specs in + * specs passed in, if Proguard should run on the given rule. {@link #createProguardAction} relies + * on this method returning an empty list if the given rule doesn't declare specs in * --java_optimization_mode=legacy. * * <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 com.google.devtools.build.lib.rules.android.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, - Iterable<Artifact> specsToInclude) { + public static ImmutableList<Artifact> collectTransitiveProguardSpecs( + RuleContext ruleContext, Iterable<Artifact> specsToInclude) { JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext); if (optMode == JavaOptimizationMode.NOOP) { return ImmutableList.of(); @@ -263,9 +262,8 @@ public abstract class ProguardHelper { ImmutableSortedSet.orderedBy(Artifact.EXEC_PATH_COMPARATOR) .addAll(proguardSpecs) .addAll(specsToInclude) - .addAll(ruleContext - .getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET) - .list()); + .addAll( + ruleContext.getPrerequisiteArtifacts(":extra_proguard_specs", Mode.TARGET).list()); for (ProguardSpecProvider dep : ruleContext.getPrerequisites("deps", Mode.TARGET, ProguardSpecProvider.class)) { builder.addAll(dep.getTransitiveProguardSpecs()); @@ -288,8 +286,8 @@ public abstract class ProguardHelper { } /** - * Creates a proguard spec that tells proguard to keep the binary's entry point, ie., the - * {@code main()} method to be invoked. + * Creates a proguard spec that tells proguard to keep the binary's entry point, ie., the {@code + * main()} method to be invoked. */ protected static Artifact generateSpecForJavaBinary( RuleContext ruleContext, String mainClassName) { @@ -305,17 +303,15 @@ public abstract class ProguardHelper { return result; } - /** - * @return true if proguard_generate_mapping is specified. - */ + /** @return true if proguard_generate_mapping is specified. */ public static final boolean genProguardMapping(AttributeMap rule) { - return rule.has("proguard_generate_mapping", Type.BOOLEAN) - && rule.get("proguard_generate_mapping", Type.BOOLEAN); + return rule.has("proguard_generate_mapping", Type.BOOLEAN) + && rule.get("proguard_generate_mapping", Type.BOOLEAN); } public static final boolean genObfuscatedConstantStringMap(AttributeMap rule) { return rule.has("proguard_generate_obfuscated_constant_string_mapping", Type.BOOLEAN) - && rule.get("proguard_generate_obfuscated_constant_string_mapping", Type.BOOLEAN); + && rule.get("proguard_generate_obfuscated_constant_string_mapping", Type.BOOLEAN); } public static ProguardOutput getProguardOutputs( @@ -357,9 +353,9 @@ public abstract class ProguardHelper { /** * 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 + * 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 - * classes in the output Jar correspond to which methods and classes in the input). The "pair" + * classes in the output Jar correspond to which methods and classes in the input). The "pair" * returned by this method indicates whether a mapping is being produced. * * <p>See the Proguard manual for the meaning of the various artifacts in play. @@ -369,10 +365,11 @@ public abstract class ProguardHelper { * @param proguardMapping optional mapping file for Proguard to apply * @param libraryJars any other Jar files that the {@code programJar} will run against * @param optimizationPasses if not null specifies to break proguard up into multiple passes with - * the given number of optimization passes. + * the given number of optimization passes. * @param proguardOutputMap mapping generated by Proguard if requested. could be null. */ - public static ProguardOutput createOptimizationActions(RuleContext ruleContext, + public static ProguardOutput createOptimizationActions( + RuleContext ruleContext, FilesToRunProvider proguard, Artifact programJar, ImmutableList<Artifact> proguardSpecs, @@ -383,21 +380,26 @@ public abstract class ProguardHelper { Artifact proguardOutputJar, JavaSemantics semantics, @Nullable Integer optimizationPasses, - @Nullable Artifact proguardOutputMap) throws InterruptedException { + @Nullable Artifact proguardOutputMap) + throws InterruptedException { JavaOptimizationMode optMode = getJavaOptimizationMode(ruleContext); Preconditions.checkArgument(optMode != JavaOptimizationMode.NOOP); Preconditions.checkArgument(optMode != JavaOptimizationMode.LEGACY || !proguardSpecs.isEmpty()); ProguardOutput output = - getProguardOutputs(proguardOutputJar, proguardSeeds, proguardUsage, ruleContext, semantics, + getProguardOutputs( + proguardOutputJar, + proguardSeeds, + proguardUsage, + ruleContext, + semantics, proguardOutputMap); - if (Iterables.size(libraryJars) > 1) { - JavaTargetAttributes attributes = new JavaTargetAttributes.Builder(semantics) - .build(); - Artifact combinedLibraryJar = getProguardTempArtifact(ruleContext, - optMode.name().toLowerCase(), "combined_library_jars.jar"); + JavaTargetAttributes attributes = new JavaTargetAttributes.Builder(semantics).build(); + Artifact combinedLibraryJar = + getProguardTempArtifact( + ruleContext, optMode.name().toLowerCase(), "combined_library_jars.jar"); new DeployArchiveBuilder(semantics, ruleContext) .setOutputJar(combinedLibraryJar) .setAttributes(attributes) @@ -408,7 +410,11 @@ public abstract class ProguardHelper { if (optimizationPasses == null) { // Run proguard as a single step. - SpawnAction.Builder builder = defaultAction( + SpawnAction.Builder proguardAction = new SpawnAction.Builder(); + CustomCommandLine.Builder commandLine = CustomCommandLine.builder(); + defaultAction( + proguardAction, + commandLine, proguard, programJar, proguardSpecs, @@ -420,34 +426,40 @@ public abstract class ProguardHelper { output.getSeeds(), output.getUsage(), output.getConstantStringObfuscatedMapping(), - output.getConfig()) + output.getConfig()); + proguardAction .setProgressMessage("Trimming binary with Proguard") .addOutput(proguardOutputJar); - - ruleContext.registerAction(builder.build(ruleContext)); + proguardAction.setCommandLine(commandLine.build()); + ruleContext.registerAction(proguardAction.build(ruleContext)); } else { // Optimization passes have been specified, so run proguard in multiple phases. - Artifact lastStageOutput = getProguardTempArtifact( - ruleContext, optMode.name().toLowerCase(), "proguard_preoptimization.jar"); - ruleContext.registerAction( - defaultAction( - proguard, - programJar, - proguardSpecs, - proguardMapping, - libraryJars, - output.getOutputJar(), - /* proguardOutputMap */ null, - /* proguardOutputProtoMap */ null, - output.getSeeds(), // ProGuard only prints seeds during INITIAL and NORMAL runtypes. - /* proguardUsage */ null, - /* constantStringObfuscatedMapping */ null, - /* proguardConfigOutput */ null) - .setProgressMessage("Trimming binary with Proguard: Verification/Shrinking Pass") - .addArgument("-runtype INITIAL") - .addArgument("-nextstageoutput") - .addOutputArgument(lastStageOutput) - .build(ruleContext)); + Artifact lastStageOutput = + getProguardTempArtifact( + ruleContext, optMode.name().toLowerCase(), "proguard_preoptimization.jar"); + SpawnAction.Builder initialAction = new SpawnAction.Builder(); + CustomCommandLine.Builder initialCommandLine = CustomCommandLine.builder(); + defaultAction( + initialAction, + initialCommandLine, + proguard, + programJar, + proguardSpecs, + proguardMapping, + libraryJars, + output.getOutputJar(), + /* proguardOutputMap */ null, + /* proguardOutputProtoMap */ null, + output.getSeeds(), // ProGuard only prints seeds during INITIAL and NORMAL runtypes. + /* proguardUsage */ null, + /* constantStringObfuscatedMapping */ null, + /* proguardConfigOutput */ null); + initialAction + .setProgressMessage("Trimming binary with Proguard: Verification/Shrinking Pass") + .addOutput(lastStageOutput); + initialCommandLine.add("-runtype INITIAL").addExecPath("-nextstageoutput", lastStageOutput); + initialAction.setCommandLine(initialCommandLine.build()); + ruleContext.registerAction(initialAction.build(ruleContext)); for (int i = 1; i <= optimizationPasses; i++) { // Run configured optimizers in order in each pass @@ -468,35 +480,48 @@ public abstract class ProguardHelper { checkState("Proguard".equals(mnemonic), "Need label to run %s", mnemonic); executable = proguard; } - Artifact optimizationOutput = getProguardTempArtifact( - ruleContext, optMode.name().toLowerCase(), mnemonic + "_optimization_" + i + ".jar"); - ruleContext.registerAction( - defaultAction( - checkNotNull(executable, "couldn't find optimizer %s", optimizer), - programJar, - proguardSpecs, - proguardMapping, - libraryJars, - output.getOutputJar(), - /* proguardOutputMap */ null, - /* proguardOutputProtoMap */ null, - /* proguardSeeds */ null, - /* proguardUsage */ null, - /* constantStringObfuscatedMapping */ null, - /* proguardConfigOutput */ null) - .setProgressMessage("Trimming binary with %s: Optimization Pass %d", mnemonic, +i) - .setMnemonic(mnemonic) - .addArgument("-runtype OPTIMIZATION") - .addArgument("-laststageoutput") - .addInputArgument(lastStageOutput) - .addArgument("-nextstageoutput") - .addOutputArgument(optimizationOutput) - .build(ruleContext)); + Artifact optimizationOutput = + getProguardTempArtifact( + ruleContext, + optMode.name().toLowerCase(), + mnemonic + "_optimization_" + i + ".jar"); + SpawnAction.Builder optimizationAction = new SpawnAction.Builder(); + CustomCommandLine.Builder optimizationCommandLine = CustomCommandLine.builder(); + defaultAction( + optimizationAction, + optimizationCommandLine, + checkNotNull(executable, "couldn't find optimizer %s", optimizer), + programJar, + proguardSpecs, + proguardMapping, + libraryJars, + output.getOutputJar(), + /* proguardOutputMap */ null, + /* proguardOutputProtoMap */ null, + /* proguardSeeds */ null, + /* proguardUsage */ null, + /* constantStringObfuscatedMapping */ null, + /* proguardConfigOutput */ null); + optimizationAction + .setProgressMessage("Trimming binary with %s: Optimization Pass %d", mnemonic, +i) + .setMnemonic(mnemonic) + .addInput(lastStageOutput) + .addOutput(optimizationOutput); + optimizationCommandLine + .add("-runtype OPTIMIZATION") + .addExecPath("-laststageoutput", lastStageOutput) + .addExecPath("-nextstageoutput", optimizationOutput); + optimizationAction.setCommandLine(optimizationCommandLine.build()); + ruleContext.registerAction(optimizationAction.build(ruleContext)); lastStageOutput = optimizationOutput; } } - SpawnAction.Builder builder = defaultAction( + SpawnAction.Builder finalAction = new SpawnAction.Builder(); + CustomCommandLine.Builder finalCommandLine = CustomCommandLine.builder(); + defaultAction( + finalAction, + finalCommandLine, proguard, programJar, proguardSpecs, @@ -505,23 +530,25 @@ public abstract class ProguardHelper { output.getOutputJar(), output.getMapping(), output.getProtoMapping(), - /* proguardSeeds */ null, // runtype FINAL does not produce seeds. + /* proguardSeeds */ null, // runtype FINAL does not produce seeds. output.getUsage(), output.getConstantStringObfuscatedMapping(), - output.getConfig()) + output.getConfig()); + finalAction .setProgressMessage("Trimming binary with Proguard: Obfuscation and Final Output Pass") - .addArgument("-runtype FINAL") - .addArgument("-laststageoutput") - .addInputArgument(lastStageOutput) + .addInput(lastStageOutput) .addOutput(proguardOutputJar); - - ruleContext.registerAction(builder.build(ruleContext)); + finalCommandLine.add("-runtype FINAL").addExecPath("-laststageoutput", lastStageOutput); + finalAction.setCommandLine(finalCommandLine.build()); + ruleContext.registerAction(finalAction.build(ruleContext)); } return output; } - private static SpawnAction.Builder defaultAction( + private static void defaultAction( + SpawnAction.Builder builder, + CustomCommandLine.Builder commandLine, FilesToRunProvider executable, Artifact programJar, ImmutableList<Artifact> proguardSpecs, @@ -535,104 +562,97 @@ public abstract class ProguardHelper { @Nullable Artifact constantStringObfuscatedMapping, @Nullable Artifact proguardConfigOutput) { - Builder builder = new SpawnAction.Builder() + builder .addInputs(libraryJars) .addInputs(proguardSpecs) .setExecutable(executable) .setMnemonic("Proguard") - .addArgument("-forceprocessing") - .addArgument("-injars") - .addInputArgument(programJar) + .addInput(programJar); + + commandLine + .add("-forceprocessing") + .addExecPath("-injars", programJar) // This is handled by the build system there is no need for proguard to check if things are // up to date. - .addArgument("-outjars") + .add("-outjars") // Don't register the output jar as an output of the action, because multiple proguard // actions will be created for optimization runs which will overwrite the jar, and only // the final proguard action will declare the output jar as an output. - .addArgument(proguardOutputJar.getExecPathString()); + .addExecPath(proguardOutputJar); for (Artifact libraryJar : libraryJars) { - builder - .addArgument("-libraryjars") - .addArgument(libraryJar.getExecPathString()); + commandLine.addExecPath("-libraryjars", libraryJar); } if (proguardMapping != null) { - builder - .addArgument("-applymapping") - .addInputArgument(proguardMapping); + builder.addInput(proguardMapping); + commandLine.addExecPath("-applymapping", proguardMapping); } for (Artifact proguardSpec : proguardSpecs) { - builder.addArgument("@" + proguardSpec.getExecPathString()); + commandLine.addPrefixedExecPath("@", proguardSpec); } if (proguardOutputMap != null) { - builder - .addArgument("-printmapping") - .addOutputArgument(proguardOutputMap); + builder.addOutput(proguardOutputMap); + commandLine.addExecPath("-printmapping", proguardOutputMap); } if (proguardOutputProtoMap != null) { - builder - .addArgument("-protomapping") - .addOutputArgument(proguardOutputProtoMap); + builder.addOutput(proguardOutputProtoMap); + commandLine.addExecPath("-protomapping", proguardOutputProtoMap); } if (constantStringObfuscatedMapping != null) { - builder - .addArgument("-obfuscatedconstantstringoutputfile") - .addOutputArgument(constantStringObfuscatedMapping); + builder.addOutput(constantStringObfuscatedMapping); + commandLine.addExecPath( + "-obfuscatedconstantstringoutputfile", constantStringObfuscatedMapping); } if (proguardSeeds != null) { - builder - .addArgument("-printseeds") - .addOutputArgument(proguardSeeds); + builder.addOutput(proguardSeeds); + commandLine.addExecPath("-printseeds", proguardSeeds); } if (proguardUsage != null) { - builder - .addArgument("-printusage") - .addOutputArgument(proguardUsage); + builder.addOutput(proguardUsage); + commandLine.addExecPath("-printusage", proguardUsage); } if (proguardConfigOutput != null) { - builder - .addArgument("-printconfiguration") - .addOutputArgument(proguardConfigOutput); + builder.addOutput(proguardConfigOutput); + commandLine.addExecPath("-printconfiguration", proguardConfigOutput); } - - return builder; } - /** - * Returns an intermediate artifact used to run Proguard. - */ + /** Returns an intermediate artifact used to run Proguard. */ public static Artifact getProguardTempArtifact( RuleContext ruleContext, String prefix, String name) { // TODO(bazel-team): Remove the redundant inclusion of the rule name, as getUniqueDirectory // includes the rulename as well. - return Preconditions.checkNotNull(ruleContext.getUniqueDirectoryArtifact( - "proguard", - Joiner.on("_").join(prefix, ruleContext.getLabel().getName(), name), - ruleContext.getBinOrGenfilesDirectory())); + return Preconditions.checkNotNull( + ruleContext.getUniqueDirectoryArtifact( + "proguard", + Joiner.on("_").join(prefix, ruleContext.getLabel().getName(), name), + ruleContext.getBinOrGenfilesDirectory())); } public static Artifact getProguardConfigArtifact(RuleContext ruleContext, String prefix) { return getProguardTempArtifact(ruleContext, prefix, "proguard.cfg"); } - /** - * Returns {@link JavaConfiguration#getJavaOptimizationMode()}. - */ + /** Returns {@link JavaConfiguration#getJavaOptimizationMode()}. */ public static JavaOptimizationMode getJavaOptimizationMode(RuleContext ruleContext) { - return ruleContext.getConfiguration().getFragment(JavaConfiguration.class) + return ruleContext + .getConfiguration() + .getFragment(JavaConfiguration.class) .getJavaOptimizationMode(); } private static Map<String, Optional<Label>> getBytecodeOptimizers(RuleContext ruleContext) { - return ruleContext.getConfiguration().getFragment(JavaConfiguration.class) + return ruleContext + .getConfiguration() + .getFragment(JavaConfiguration.class) .getBytecodeOptimizers(); } } |