diff options
author | Michael Staib <mstaib@google.com> | 2016-03-16 21:52:19 +0000 |
---|---|---|
committer | Lukacs Berki <lberki@google.com> | 2016-03-17 10:08:07 +0000 |
commit | 8c1138c0458f780f349a6d1e21821ca932c238bc (patch) | |
tree | e57bcbd981a4b04d6f3339981ee40d251901f19b /src/main/java/com/google/devtools/build/lib/rules/android | |
parent | e5fac8175fbdd158139ff2446e83718b2a85b8b4 (diff) |
Compile base classpaths for Bazel Jack support in android_sdk.
This also enables Jack support to compile with the Java bootclasspath
when running over non-Android rules. This is akin to how normal javac
support works - android_ rules are compiled with android.jar, while
java_libraries are compiled with special flags but the normal compile
time bootclasspath.
As of this change, the android_jack attribute on android_sdk is now
deprecated, and has no further effect. Because it was always optional,
this isn't really much of a change, it just means that now it does
nothing even if you DO specify it.
Because Jack support is still experimental, this should have no effect
on most users.
RELNOTES[INC]: android_sdk now compiles android_jack on the fly from
android_jar, which means android_jar must be a jar and android_jack is
now deprecated. The Jack tools (jack, jill, resource_extractor) must
be specified.
--
MOS_MIGRATED_REVID=117386373
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/android')
6 files changed, 185 insertions, 48 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java index bd1dd656ee..a1bd85521c 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidCommon.java @@ -558,7 +558,10 @@ public class AndroidCommon { .setOutputArtifact( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_JACK_FILE)) // tools - .setAndroidSdk(sdk) + .setJackBinary(sdk.getJack()) + .setJillBinary(sdk.getJill()) + .setResourceExtractorBinary(sdk.getResourceExtractor()) + .setJackBaseClasspath(sdk.getAndroidBaseClasspathForJack()) // sources .addJavaSources(attributes.getSourceFiles()) .addSourceJars(attributes.getSourceJars()) 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 c1d12ed7ee..1b964d9d12 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 @@ -337,15 +337,12 @@ public final class AndroidRuleClasses { .add(attr("adb", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE).exec()) .add(attr("framework_aidl", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE)) .add(attr("aidl", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE).exec()) - .add(attr("android_jar", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE)) + .add(attr("android_jar", LABEL).mandatory().cfg(HOST).allowedFileTypes(JavaSemantics.JAR)) .add(attr("shrinked_android_jar", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE)) .add( attr("android_jack", LABEL) .cfg(HOST) - .allowedFileTypes(ANY_FILE) - // TODO(bazel-team): Remove defaults and make mandatory when android_sdk targets - // have been updated to include manually specified Jack attributes. - .value(environment.getToolsLabel("//tools/android/jack:android_jack"))) + .allowedFileTypes(ANY_FILE)) .add(attr("annotations_jar", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE)) .add(attr("main_dex_classes", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE)) .add(attr("apkbuilder", LABEL).mandatory().cfg(HOST).allowedFileTypes(ANY_FILE).exec()) @@ -355,19 +352,27 @@ public final class AndroidRuleClasses { .cfg(HOST) .allowedFileTypes(ANY_FILE) .exec() - .value(environment.getToolsLabel("//tools/android/jack:jack"))) + .mandatory()) .add( attr("jill", LABEL) .cfg(HOST) .allowedFileTypes(ANY_FILE) .exec() - .value(environment.getToolsLabel("//tools/android/jack:jill"))) + .mandatory()) .add( attr("resource_extractor", LABEL) .cfg(HOST) .allowedFileTypes(ANY_FILE) .exec() - .value(environment.getToolsLabel("//tools/android/jack:resource_extractor"))) + .mandatory()) + .add( + attr(":java_toolchain", LABEL) + .allowedRuleClasses("java_toolchain") + .value(JavaSemantics.JAVA_TOOLCHAIN)) + .add( + attr("$javac_bootclasspath", LABEL) + .cfg(HOST) + .value(environment.getLabel(JavaSemantics.JAVAC_BOOTCLASSPATH_LABEL))) .build(); } 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 2d61a18cba..016fedf990 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 @@ -13,6 +13,7 @@ // limitations under the License. package com.google.devtools.build.lib.rules.android; +import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.analysis.ConfiguredTarget; import com.google.devtools.build.lib.analysis.FilesToRunProvider; @@ -20,13 +21,18 @@ 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.RunfilesProvider; +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.packages.AggregatingAttributeMapper; import com.google.devtools.build.lib.rules.RuleConfiguredTargetFactory; +import com.google.devtools.build.lib.rules.java.BaseJavaCompilationHelper; import com.google.devtools.build.lib.rules.java.JavaConfiguration; +import com.google.devtools.build.lib.rules.java.JavaToolchainProvider; import com.google.devtools.build.lib.syntax.Type; +import java.util.Collection; + /** * Implementation of the {@code android_sdk} rule. */ @@ -59,7 +65,20 @@ public class AndroidSdk implements RuleConfiguredTargetFactory { Artifact androidJar = ruleContext.getPrerequisiteArtifact("android_jar", Mode.HOST); Artifact shrinkedAndroidJar = ruleContext.getPrerequisiteArtifact("shrinked_android_jar", Mode.HOST); - Artifact androidJack = ruleContext.getPrerequisiteArtifact("android_jack", Mode.HOST); + // Because all Jack actions using this android_sdk will need Jack versions of the Android and + // Java classpaths, pre-translate the jars for Android and Java targets here. (They will only + // be run if needed, as usual for Bazel.) + NestedSet<Artifact> androidBaseClasspathForJack = + convertClasspathJarsToJack( + ruleContext, jack, jill, resourceExtractor, ImmutableList.of(androidJar)); + NestedSet<Artifact> javaBaseClasspathForJack = + convertClasspathJarsToJack( + ruleContext, + jack, + jill, + resourceExtractor, + BaseJavaCompilationHelper.getBootClasspath( + ruleContext, JavaToolchainProvider.fromRuleContext(ruleContext), "")); Artifact annotationsJar = ruleContext.getPrerequisiteArtifact("annotations_jar", Mode.HOST); Artifact mainDexClasses = ruleContext.getPrerequisiteArtifact("main_dex_classes", Mode.HOST); @@ -75,7 +94,8 @@ public class AndroidSdk implements RuleConfiguredTargetFactory { frameworkAidl, androidJar, shrinkedAndroidJar, - androidJack, + androidBaseClasspathForJack, + javaBaseClasspathForJack, annotationsJar, mainDexClasses, adb, @@ -93,4 +113,27 @@ public class AndroidSdk implements RuleConfiguredTargetFactory { .setFilesToBuild(NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER)) .build(); } + + private NestedSet<Artifact> convertClasspathJarsToJack( + RuleContext ruleContext, + FilesToRunProvider jack, + FilesToRunProvider jill, + FilesToRunProvider resourceExtractor, + Collection<Artifact> jars) { + return new JackCompilationHelper.Builder() + // bazel infrastructure + .setRuleContext(ruleContext) + // configuration + .setTolerant() + // tools + .setJackBinary(jack) + .setJillBinary(jill) + .setResourceExtractorBinary(resourceExtractor) + .setJackBaseClasspath(NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER)) + // sources + .addCompiledJars(jars) + .build() + .compileAsLibrary() + .getTransitiveJackClasspathLibraries(); + } } diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java index 522c41f3ae..2a3065fc42 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidSdkProvider.java @@ -19,6 +19,7 @@ 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.TransitiveInfoProvider; +import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; /** @@ -31,7 +32,8 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { private final Artifact frameworkAidl; private final Artifact androidJar; private final Artifact shrinkedAndroidJar; - private final Artifact androidJack; + private final NestedSet<Artifact> androidBaseClasspathForJack; + private final NestedSet<Artifact> javaBaseClasspathForJack; private final Artifact annotationsJar; private final Artifact mainDexClasses; private final FilesToRunProvider adb; @@ -51,7 +53,8 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { Artifact frameworkAidl, Artifact androidJar, Artifact shrinkedAndroidJar, - Artifact androidJack, + NestedSet<Artifact> androidBaseClasspathForJack, + NestedSet<Artifact> javaBaseClasspathForJack, Artifact annotationsJar, Artifact mainDexClasses, FilesToRunProvider adb, @@ -70,7 +73,8 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { this.frameworkAidl = frameworkAidl; this.androidJar = androidJar; this.shrinkedAndroidJar = shrinkedAndroidJar; - this.androidJack = androidJack; + this.androidBaseClasspathForJack = androidBaseClasspathForJack; + this.javaBaseClasspathForJack = javaBaseClasspathForJack; this.annotationsJar = annotationsJar; this.mainDexClasses = mainDexClasses; this.adb = adb; @@ -131,8 +135,20 @@ public final class AndroidSdkProvider implements TransitiveInfoProvider { return shrinkedAndroidJar; } - public Artifact getAndroidJack() { - return androidJack; + /** + * Returns the set of jack files to be used as a base classpath for jack compilation of Android + * rules, typically a Jack translation of the jar returned by {@link getAndroidJar}. + */ + public NestedSet<Artifact> getAndroidBaseClasspathForJack() { + return androidBaseClasspathForJack; + } + + /** + * Returns the set of jack files to be used as a base classpath for jack compilation of Java + * rules, typically a Jack translation of the jars in the Java bootclasspath. + */ + public NestedSet<Artifact> getJavaBaseClasspathForJack() { + return javaBaseClasspathForJack; } public Artifact getAnnotationsJar() { diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/JackAspect.java b/src/main/java/com/google/devtools/build/lib/rules/android/JackAspect.java index b76690df11..a167f38ba9 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/JackAspect.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/JackAspect.java @@ -71,7 +71,10 @@ public final class JackAspect implements NativeAspectFactory, ConfiguredAspectFa // configuration .setOutputArtifact(jackLibraryOutput) // tools - .setAndroidSdk(androidSdk) + .setJackBinary(androidSdk.getJack()) + .setJillBinary(androidSdk.getJill()) + .setResourceExtractorBinary(androidSdk.getResourceExtractor()) + .setJackBaseClasspath(androidSdk.getJavaBaseClasspathForJack()) // sources .addJavaSources(sourceProvider.getSourceFiles()) .addSourceJars(sourceProvider.getSourceJars()) diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/JackCompilationHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/JackCompilationHelper.java index f49ed047be..c067d366aa 100644 --- a/src/main/java/com/google/devtools/build/lib/rules/android/JackCompilationHelper.java +++ b/src/main/java/com/google/devtools/build/lib/rules/android/JackCompilationHelper.java @@ -76,6 +76,8 @@ public final class JackCompilationHelper { static final String SANITY_CHECKS_OFF = "off"; /** Value of the sanity checks flag which enables sanity checks. */ static final String SANITY_CHECKS_ON = "on"; + /** Flag to enable tolerant mode in Jill, for compiling special jars (e.g., bootclasspath). */ + static final String TOLERANT = "--tolerant"; /** Flag to indicate the classpath of Jack libraries, separated by semicolons. */ static final String CLASSPATH = "-cp"; @@ -112,6 +114,8 @@ public final class JackCompilationHelper { /** True to use Jack's internal sanity checks, trading speed for crash-on-bugs. */ private final boolean useSanityChecks; + /** True to make Jill more tolerant, when compiling special jars (e.g., bootclasspath) */ + private final boolean useTolerant; /** Binary used to extract resources from a jar file. */ private final FilesToRunProvider resourceExtractorBinary; @@ -119,11 +123,15 @@ public final class JackCompilationHelper { private final FilesToRunProvider jackBinary; /** Binary used to convert jars to Jack libraries. */ private final FilesToRunProvider jillBinary; - /** Jack library containing Android base classes. This will be placed first on the classpath. */ - private final Artifact androidBaseLibraryForJack; + /** + * Jack libraries containing Android/Java base classes. + * + * <p>These will be placed first on the classpath. + */ + private final NestedSet<Artifact> baseClasspath; - /** The destination for the Jack artifact to be created. */ - private final Artifact outputArtifact; + /** The destination for the Jack artifact to be created, or null to skip this. */ + @Nullable private final Artifact outputArtifact; /** Java files for the rule's Jack library. */ private final ImmutableSet<Artifact> javaSources; @@ -172,11 +180,12 @@ public final class JackCompilationHelper { private JackCompilationHelper( RuleContext ruleContext, boolean useSanityChecks, + boolean useTolerant, FilesToRunProvider resourceExtractorBinary, FilesToRunProvider jackBinary, FilesToRunProvider jillBinary, - Artifact androidJackLibrary, - Artifact outputArtifact, + NestedSet<Artifact> baseClasspath, + @Nullable Artifact outputArtifact, ImmutableSet<Artifact> javaSources, ImmutableSet<Artifact> sourceJars, ImmutableMap<PathFragment, Artifact> resources, @@ -190,10 +199,11 @@ public final class JackCompilationHelper { ImmutableSet<Artifact> dexJars) { this.ruleContext = ruleContext; this.useSanityChecks = useSanityChecks; + this.useTolerant = useTolerant; this.resourceExtractorBinary = resourceExtractorBinary; this.jackBinary = jackBinary; this.jillBinary = jillBinary; - this.androidBaseLibraryForJack = androidJackLibrary; + this.baseClasspath = baseClasspath; this.outputArtifact = outputArtifact; this.javaSources = javaSources; this.sourceJars = sourceJars; @@ -329,24 +339,26 @@ public final class JackCompilationHelper { .addTransitive(classpathJacks) .build(); - // android.jack needs to be first in the set's iteration order, as it's the base library. + // The base classpath needs to be first in the set's iteration order. // Then any jars or jack files specified directly, then dependencies from providers. NestedSet<Artifact> classpath = new NestedSetBuilder<Artifact>(Order.NAIVE_LINK_ORDER) - .add(androidBaseLibraryForJack) + .addTransitive(baseClasspath) .addTransitive(transitiveClasspath) .build(); NestedSetBuilder<Artifact> exports = new NestedSetBuilder<>(Order.NAIVE_LINK_ORDER); NestedSetBuilder<Artifact> dexContents = new NestedSetBuilder<>(Order.NAIVE_LINK_ORDER); - if (javaSources.isEmpty() && sourceJars.isEmpty() && resources.isEmpty()) { - // We still have to create SOMETHING to fulfill the artifact, but man, screw it - buildEmptyJackAction(); - } else { - buildJackAction(javaSources, sourceJars, resources, classpath); - exports.add(outputArtifact); - dexContents.add(outputArtifact); + if (outputArtifact != null) { + if (javaSources.isEmpty() && sourceJars.isEmpty() && resources.isEmpty()) { + // We still have to create SOMETHING to fulfill the artifact, but man, screw it + buildEmptyJackAction(); + } else { + buildJackAction(javaSources, sourceJars, resources, classpath); + exports.add(outputArtifact); + dexContents.add(outputArtifact); + } } // These need to be added now so that they can be after the outputArtifact (if present). @@ -374,9 +386,14 @@ public final class JackCompilationHelper { PARTIAL_JACK_DIRECTORY, FileSystemUtils.replaceExtension(jar.getRootRelativePath(), ".jack"), ruleContext.getBinOrGenfilesDirectory()); - ruleContext.registerAction( + SpawnAction.Builder builder = new SpawnAction.Builder() - .setExecutable(jillBinary) + .setExecutable(jillBinary); + if (useTolerant) { + builder.addArgument(TOLERANT); + } + ruleContext.registerAction( + builder .addArgument(JILL_OUTPUT) .addOutputArgument(result) .addInputArgument(jar) @@ -526,8 +543,21 @@ public final class JackCompilationHelper { /** Rule context used to build and register actions. */ @Nullable private RuleContext ruleContext; - /** Set of Android tools used to pick up the Jack tools. */ - @Nullable private AndroidSdkProvider androidSdk; + /** Whether to enable tolerant mode in Jill, e.g., when compiling a bootclasspath. */ + private boolean useTolerant; + + /** Binary used to extract resources from a jar file. */ + @Nullable private FilesToRunProvider resourceExtractorBinary; + /** Binary used to build Jack libraries and dex files. */ + @Nullable private FilesToRunProvider jackBinary; + /** Binary used to convert jars to Jack libraries. */ + @Nullable private FilesToRunProvider jillBinary; + /** + * Set of Jack libraries containing Android/Java base classes. + * + * <p>These will be placed first on the classpath. + */ + @Nullable private NestedSet<Artifact> baseClasspath; /** The destination for the Jack artifact to be created. */ @Nullable private Artifact outputArtifact; @@ -594,6 +624,8 @@ public final class JackCompilationHelper { * * <p>The artifact specified will always be generated, although it may be empty if there are no * sources. + * + * <p>This method must be called if any of addJavaSources, addSourceJars, or addResources is. */ public JackCompilationHelper.Builder setOutputArtifact(Artifact outputArtifact) { this.outputArtifact = Preconditions.checkNotNull(outputArtifact); @@ -601,11 +633,43 @@ public final class JackCompilationHelper { } /** - * Sets the tools bundle containing Jack, Jill, the resource extractor, and the Android base - * library in Jack format. + * Sets the Jack binary used to perform operations on Jack libraries. + */ + public JackCompilationHelper.Builder setJackBinary(FilesToRunProvider jackBinary) { + this.jackBinary = Preconditions.checkNotNull(jackBinary); + return this; + } + + /** + * Sets the Jill binary used to translate jars to jack files. */ - public JackCompilationHelper.Builder setAndroidSdk(AndroidSdkProvider androidSdk) { - this.androidSdk = Preconditions.checkNotNull(androidSdk); + public JackCompilationHelper.Builder setJillBinary(FilesToRunProvider jillBinary) { + this.jillBinary = Preconditions.checkNotNull(jillBinary); + return this; + } + + /** + * Sets the resource extractor binary used to extract resources from jars. + */ + public JackCompilationHelper.Builder setResourceExtractorBinary( + FilesToRunProvider resourceExtractorBinary) { + this.resourceExtractorBinary = Preconditions.checkNotNull(resourceExtractorBinary); + return this; + } + + /** + * Sets the base classpath, containing core classes (android.jar or Java bootclasspath). + */ + public JackCompilationHelper.Builder setJackBaseClasspath(NestedSet<Artifact> baseClasspath) { + this.baseClasspath = Preconditions.checkNotNull(baseClasspath); + return this; + } + + /** + * Sets Jill to be tolerant, e.g., when translating a jar from the Java bootclasspath to jack. + */ + public JackCompilationHelper.Builder setTolerant() { + this.useTolerant = true; return this; } @@ -780,25 +844,28 @@ public final class JackCompilationHelper { */ public JackCompilationHelper build() { Preconditions.checkNotNull(ruleContext); - Preconditions.checkNotNull(androidSdk); boolean useSanityChecks = ruleContext .getFragment(AndroidConfiguration.class) .isJackSanityChecked(); - FilesToRunProvider jackBinary = androidSdk.getJack(); - FilesToRunProvider jillBinary = androidSdk.getJill(); - FilesToRunProvider resourceExtractorBinary = androidSdk.getResourceExtractor(); - Artifact androidBaseLibraryForJack = androidSdk.getAndroidJack(); + + // It's okay not to have an outputArtifact if there is nothing to build. + // e.g., if only translating jars with Jill, no final jack library will be created. + // But if there is something to build, enforce that one has been specified. + if (!javaSources.isEmpty() || !sourceJars.isEmpty() || !resources.isEmpty()) { + Preconditions.checkNotNull(outputArtifact); + } return new JackCompilationHelper( ruleContext, useSanityChecks, + useTolerant, Preconditions.checkNotNull(resourceExtractorBinary), Preconditions.checkNotNull(jackBinary), Preconditions.checkNotNull(jillBinary), - Preconditions.checkNotNull(androidBaseLibraryForJack), - Preconditions.checkNotNull(outputArtifact), + Preconditions.checkNotNull(baseClasspath), + outputArtifact, ImmutableSet.copyOf(javaSources), ImmutableSet.copyOf(sourceJars), ImmutableMap.copyOf(resources), |