From d6f6b7dac79d122ba81d7e2b0f53feac7b225f1d Mon Sep 17 00:00:00 2001 From: Lukacs Berki Date: Thu, 24 Sep 2015 08:19:30 +0000 Subject: Add a main_dex_proguard_specs attribute to android_binary that lets users specify which classes should go into the main dex. This mode uses Proguard to determine the dependencies of these classes, which means that no error-prone manual listing required like in multidex="manual" mode. RELNOTES: android_binary now has a main_dex_proguard_specs attribute to specify which classes should be in the main dex. -- MOS_MIGRATED_REVID=103824119 --- .../build/lib/rules/android/AndroidBinary.java | 29 ++++++++++++++++++---- .../lib/rules/android/AndroidRuleClasses.java | 7 ++++++ .../build/lib/analysis/util/BuildViewTestCase.java | 20 ++++++++++++--- 3 files changed, 47 insertions(+), 9 deletions(-) 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 81db9ac7cf..e0a057fe97 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 @@ -121,6 +121,15 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { JavaSemantics javaSemantics, AndroidSemantics androidSemantics, List depsAttributes) throws InterruptedException { + + if (getMultidexMode(ruleContext) != MultidexMode.LEGACY + && ruleContext.attributes().isAttributeValueExplicitlySpecified( + "main_dex_proguard_specs")) { + ruleContext.attributeError("main_dex_proguard_specs", "The 'main_dex_proguard_specs' " + + "attribute is only allowed if 'multidex' is set to 'legacy'"); + return null; + } + // TODO(bazel-team): Find a way to simplify this code. // treeKeys() means that the resulting map sorts the entries by key, which is necessary to // ensure determinism. @@ -1005,7 +1014,7 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { // Process the input jar through Proguard into an intermediate, streamlined jar. Artifact strippedJar = AndroidBinary.getDxArtifact(ruleContext, "main_dex_intermediate.jar"); AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); - ruleContext.registerAction(new SpawnAction.Builder() + SpawnAction.Builder streamlinedBuilder = new SpawnAction.Builder() .addOutput(strippedJar) .setExecutable(sdk.getProguard()) .setProgressMessage("Generating streamlined input jar for main dex classes list") @@ -1021,10 +1030,20 @@ public abstract class AndroidBinary implements RuleConfiguredTargetFactory { .addArgument("-forceprocessing") .addArgument("-dontoptimize") .addArgument("-dontobfuscate") - .addArgument("-dontpreverify") - .addArgument("-include") - .addInputArgument(sdk.getMainDexClasses()) - .build(ruleContext)); + .addArgument("-dontpreverify"); + + List specs = ruleContext.getPrerequisiteArtifacts( + "main_dex_proguard_specs", Mode.TARGET).list(); + if (specs.isEmpty()) { + specs = ImmutableList.of(sdk.getMainDexClasses()); + } + + for (Artifact spec : specs) { + streamlinedBuilder.addArgument("-include"); + streamlinedBuilder.addInputArgument(spec); + } + + ruleContext.registerAction(streamlinedBuilder.build(ruleContext)); // Create the main dex classes list. Artifact mainDexList = AndroidBinary.getDxArtifact(ruleContext, "main_dex_list.txt"); 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 2b80cb1b7a..bbab1a54ab 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 @@ -650,6 +650,13 @@ com/google/common/base/Objects.class Must be used with multidex="manual_main_dex". */ .add(attr("main_dex_list", LABEL).legacyAllowAnyFileType()) + /* + Files to be used as the Proguard specifications to determine classes that must be kept in + the main dex. + ${SYNOPSIS} + Only allowed if the multidex attribute is set to legacy. + */ + .add(attr("main_dex_proguard_specs", LABEL_LIST).legacyAllowAnyFileType()) /* Files to be used as Proguard specification. ${SYNOPSIS} diff --git a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java index 3d9b5d3509..ff22af1993 100644 --- a/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java +++ b/src/test/java/com/google/devtools/build/lib/analysis/util/BuildViewTestCase.java @@ -749,7 +749,7 @@ public abstract class BuildViewTestCase extends FoundationTestCase { String... lines) throws Exception { eventCollector.clear(); ConfiguredTarget target = scratchConfiguredTarget(packageName, ruleName, - lines); + lines); assertFalse( "Rule '" + "//" + packageName + ":" + ruleName + "' did contain an error", view.hasErrors(target)); @@ -1411,7 +1411,7 @@ public abstract class BuildViewTestCase extends FoundationTestCase { protected String getErrorMsgWrongAttributeValue(String value, String... expected) { return String.format("has to be one of %s instead of '%s'", - StringUtil.joinEnglishList(ImmutableSet.copyOf(expected), "or", "'"), value); + StringUtil.joinEnglishList(ImmutableSet.copyOf(expected), "or", "'"), value); } protected String getErrorMsgMandatoryProviderMissing(String offendingRule, String providerName) { @@ -1535,9 +1535,21 @@ public abstract class BuildViewTestCase extends FoundationTestCase { */ protected Artifact artifactByPath(Iterable artifacts, String... suffixes) { Artifact artifact = getFirstArtifactEndingWith(artifacts, suffixes[0]); - + Action action = null; for (int i = 1; i < suffixes.length; i++) { - artifacts = getGeneratingAction(artifact).getInputs(); + if (artifact == null) { + if (action == null) { + throw new IllegalStateException("No suffix " + suffixes[0] + " among artifacts: " + + ActionsTestUtil.baseArtifactNames(artifacts)); + } else { + throw new IllegalStateException("No suffix " + suffixes[i] + + " among inputs of action " + action.describe() + ": " + + ActionsTestUtil.baseArtifactNames(artifacts)); + } + } + + action = getGeneratingAction(artifact); + artifacts = action.getInputs(); artifact = getFirstArtifactEndingWith(artifacts, suffixes[i]); } -- cgit v1.2.3