// Copyright 2015 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.android; import static com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode.DEFAULT; import static com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode.ERROR; import static com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode.STRICT; import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.devtools.build.lib.actions.Artifact; import com.google.devtools.build.lib.actions.ResourceSet; import com.google.devtools.build.lib.analysis.AnalysisUtils; import com.google.devtools.build.lib.analysis.FilesToRunProvider; import com.google.devtools.build.lib.analysis.OutputGroupProvider; 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.analysis.actions.FileWriteAction; import com.google.devtools.build.lib.analysis.actions.SpawnAction; import com.google.devtools.build.lib.analysis.config.BuildConfiguration.StrictDepsMode; 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.BuildType; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceContainer; import com.google.devtools.build.lib.rules.android.AndroidResourcesProvider.ResourceType; import com.google.devtools.build.lib.rules.android.AndroidRuleClasses.MultidexMode; import com.google.devtools.build.lib.rules.cpp.CcLinkParams; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsProvider; import com.google.devtools.build.lib.rules.cpp.CcLinkParamsStore; import com.google.devtools.build.lib.rules.cpp.CcNativeLibraryProvider; import com.google.devtools.build.lib.rules.cpp.CppFileTypes; import com.google.devtools.build.lib.rules.cpp.LinkerInput; import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment; import com.google.devtools.build.lib.rules.java.JavaCcLinkParamsProvider; import com.google.devtools.build.lib.rules.java.JavaCommon; import com.google.devtools.build.lib.rules.java.JavaCompilationArgs; import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType; import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider; import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts; import com.google.devtools.build.lib.rules.java.JavaCompilationHelper; import com.google.devtools.build.lib.rules.java.JavaNativeLibraryProvider; import com.google.devtools.build.lib.rules.java.JavaPluginInfoProvider; import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider; import com.google.devtools.build.lib.rules.java.JavaRuntimeJarProvider; import com.google.devtools.build.lib.rules.java.JavaSemantics; import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider; import com.google.devtools.build.lib.rules.java.JavaTargetAttributes; import com.google.devtools.build.lib.rules.java.JavaUtil; import com.google.devtools.build.lib.syntax.Type; import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.annotation.Nullable; /** * A helper class for android rules. * *

Helps create the java compilation as well as handling the exporting of the java compilation * artifacts to the other rules. */ public class AndroidCommon { private final RuleContext ruleContext; private final JavaCommon javaCommon; private NestedSet compileTimeDependencyArtifacts; private NestedSet filesToBuild; private NestedSet transitiveNeverlinkLibraries = NestedSetBuilder.emptySet(Order.STABLE_ORDER); private Iterable topLevelSourceJars = ImmutableList.of(); private NestedSet transitiveSourceJars = NestedSetBuilder.emptySet(Order.STABLE_ORDER); private JavaCompilationArgs javaCompilationArgs = JavaCompilationArgs.EMPTY_ARGS; private JavaCompilationArgs recursiveJavaCompilationArgs = JavaCompilationArgs.EMPTY_ARGS; private JavaPluginInfoProvider transitiveJavaPluginInfoProvider = JavaPluginInfoProvider.EMPTY; private JackCompilationHelper jackCompilationHelper; private Artifact classJar; private Artifact iJar; private Artifact srcJar; private Artifact genClassJar; private Artifact genSourceJar; private NestedSet transitiveResources; private boolean asNeverLink; private boolean exportDeps; private Artifact manifestProtoOutput; private AndroidIdlHelper idlHelper; public AndroidCommon(RuleContext ruleContext, JavaCommon javaCommon) { this.ruleContext = ruleContext; this.javaCommon = javaCommon; this.asNeverLink = JavaCommon.isNeverLink(ruleContext); } /** * Creates a new AndroidCommon. * @param ruleContext The rule context associated with this instance. * @param common the JavaCommon instance * @param asNeverLink Boolean to indicate if this rule should be treated as a compile time dep * by consuming rules. * @param exportDeps Boolean to indicate if the dependencies should be treated as "exported" deps. */ public AndroidCommon( RuleContext ruleContext, JavaCommon common, boolean asNeverLink, boolean exportDeps) { this.ruleContext = ruleContext; this.asNeverLink = asNeverLink; this.exportDeps = exportDeps; this.javaCommon = common; } /** * Collects the transitive neverlink dependencies. * * @param ruleContext the context of the rule neverlink deps are to be computed for * @param deps the targets to be treated as dependencies * @param runtimeJars the runtime jars produced by the rule (non-transitive) * * @return a nested set of the neverlink deps. */ public static NestedSet collectTransitiveNeverlinkLibraries( RuleContext ruleContext, Iterable deps, ImmutableList runtimeJars) { NestedSetBuilder builder = NestedSetBuilder.naiveLinkOrder(); for (AndroidNeverLinkLibrariesProvider provider : AnalysisUtils.getProviders(deps, AndroidNeverLinkLibrariesProvider.class)) { builder.addTransitive(provider.getTransitiveNeverLinkLibraries()); } if (JavaCommon.isNeverLink(ruleContext)) { builder.addAll(runtimeJars); for (JavaCompilationArgsProvider provider : AnalysisUtils.getProviders( deps, JavaCompilationArgsProvider.class)) { builder.addTransitive(provider.getRecursiveJavaCompilationArgs().getRuntimeJars()); } } return builder.build(); } /** * Creates an action that converts {@code jarToDex} to a dex file. The output will be stored in * the {@link com.google.devtools.build.lib.actions.Artifact} {@code dxJar}. */ public static void createDexAction( RuleContext ruleContext, Artifact jarToDex, Artifact classesDex, List dexOptions, boolean multidex, Artifact mainDexList) { List args = new ArrayList<>(); args.add("--dex"); // Add --no-locals to coverage builds. Otherwise local variable debug information is not // preserved, which leads to runtime errors. if (ruleContext.getConfiguration().isCodeCoverageEnabled()) { args.add("--no-locals"); } // Multithreaded dex does not work when using --multi-dex. if (!multidex) { // Multithreaded dex tends to run faster, but only up to about 5 threads (at which point the // law of diminishing returns kicks in). This was determined experimentally, with 5-thread dex // performing about 25% faster than 1-thread dex. args.add("--num-threads=5"); } args.addAll(dexOptions); if (multidex) { args.add("--multi-dex"); if (mainDexList != null) { args.add("--main-dex-list=" + mainDexList.getExecPathString()); } } args.add("--output=" + classesDex.getExecPathString()); args.add(jarToDex.getExecPathString()); SpawnAction.Builder builder = new SpawnAction.Builder() .setExecutable(AndroidSdkProvider.fromRuleContext(ruleContext).getDx()) .addInput(jarToDex) .addOutput(classesDex) .addArguments(args) .setProgressMessage("Converting " + jarToDex.getExecPathString() + " to dex format") .setMnemonic("AndroidDexer") .setResources(ResourceSet.createWithRamCpuIo(4096.0, 5.0, 0.0)); if (mainDexList != null) { builder.addInput(mainDexList); } ruleContext.registerAction(builder.build(ruleContext)); } public static AndroidIdeInfoProvider createAndroidIdeInfoProvider( RuleContext ruleContext, AndroidSemantics semantics, AndroidIdlHelper idlHelper, ResourceApk resourceApk, Artifact zipAlignedApk, Iterable apksUnderTest) { AndroidIdeInfoProvider.Builder ideInfoProviderBuilder = new AndroidIdeInfoProvider.Builder() .setIdlClassJar(idlHelper.getIdlClassJar()) .setIdlSourceJar(idlHelper.getIdlSourceJar()) .addIdlParcelables(idlHelper.getIdlParcelables()) .addIdlSrcs(idlHelper.getIdlSources()) .addIdlGeneratedJavaFiles(idlHelper.getIdlGeneratedJavaSources()) .addAllApksUnderTest(apksUnderTest); if (zipAlignedApk != null) { ideInfoProviderBuilder.setApk(zipAlignedApk); } // If the rule defines resources, put those in the IDE info. Otherwise, proxy the data coming // from the android_resources rule in its direct dependencies, if such a thing exists. if (LocalResourceContainer.definesAndroidResources(ruleContext.attributes())) { ideInfoProviderBuilder .addResourceSources(resourceApk.getPrimaryResource().getArtifacts(ResourceType.RESOURCES)) .addAssetSources( resourceApk.getPrimaryResource().getArtifacts(ResourceType.ASSETS), getAssetDir(ruleContext)) // Sets the possibly merged manifest and the raw manifest. .setGeneratedManifest(resourceApk.getPrimaryResource().getManifest()) .setManifest(ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET)); } else { semantics.addNonLocalResources(ruleContext, resourceApk, ideInfoProviderBuilder); } return ideInfoProviderBuilder.build(); } public static String getJavaPackage(RuleContext ruleContext) { if (ruleContext.attributes().isAttributeValueExplicitlySpecified("custom_package")) { return ruleContext.attributes().get("custom_package", Type.STRING); } else { PathFragment nameFragment = ruleContext.getRule().getPackage().getNameFragment(); String packageName = JavaUtil.getJavaFullClassname(nameFragment); if (packageName != null) { return packageName; } else { // This is a workaround for libraries that don't follow the standard Bazel package format return nameFragment.getPathString().replace('/', '.'); } } } Artifact compileDexWithJack( MultidexMode mode, Optional mainDexList, Collection proguardSpecs) { return jackCompilationHelper.compileAsDex(mode, mainDexList, proguardSpecs); } public static NestedSet getTransitiveResourceContainers( RuleContext ruleContext, boolean withDeps) { // Traverse through all android_library targets looking for resources NestedSetBuilder resourcesBuilder = NestedSetBuilder.naiveLinkOrder(); List attributes = new ArrayList<>(); attributes.add("resources"); if (withDeps) { attributes.add("deps"); } for (String attribute : attributes) { if (!ruleContext.attributes().has(attribute, BuildType.LABEL) && !ruleContext.attributes().has(attribute, BuildType.LABEL_LIST)) { continue; } for (AndroidResourcesProvider resources : ruleContext.getPrerequisites(attribute, Mode.TARGET, AndroidResourcesProvider.class)) { resourcesBuilder.addTransitive(resources.getTransitiveAndroidResources()); } } return resourcesBuilder.build(); } private void compileResources( JavaSemantics javaSemantics, JavaCompilationArtifacts.Builder artifactsBuilder, JavaTargetAttributes.Builder attributes, NestedSet resourceContainers, ResourceContainer updatedResources) throws InterruptedException { Artifact binaryResourcesJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_CLASS_JAR); compileResourceJar(javaSemantics, binaryResourcesJar, updatedResources.getJavaSourceJar()); // combined resource constants needs to come even before own classes that may contain // local resource constants artifactsBuilder.addRuntimeJar(binaryResourcesJar); // Repackages the R.java for each dependency package and places the resultant jars // before the dependency libraries to ensure that the generated resource ids are // correct. createJarJarActions(attributes, resourceContainers, updatedResources.getJavaPackage(), binaryResourcesJar); } private void compileResourceJar( JavaSemantics javaSemantics, Artifact binaryResourcesJar, Artifact javaSourceJar) { JavaCompilationArtifacts.Builder javaArtifactsBuilder = new JavaCompilationArtifacts.Builder(); JavaTargetAttributes.Builder javacJarAttributes = new JavaTargetAttributes.Builder(javaSemantics); javacJarAttributes.addSourceJar(javaSourceJar); JavaCompilationHelper javacHelper = new JavaCompilationHelper( ruleContext, javaSemantics, getJavacOpts(), javacJarAttributes); Artifact outputDepsProto = javacHelper.createOutputDepsProtoArtifact(binaryResourcesJar, javaArtifactsBuilder); javacHelper.createCompileActionWithInstrumentation( binaryResourcesJar, null /* manifestProtoOutput */, null /* genSourceJar */, outputDepsProto, javaArtifactsBuilder); } private void createJarJarActions( JavaTargetAttributes.Builder attributes, Iterable resourceContainers, String originalPackage, Artifact binaryResourcesJar) { // Now use jarjar for the rest of the resources. We need to make a copy // of the final generated resources for each of the targets included in // the transitive closure of this binary. for (ResourceContainer otherContainer : resourceContainers) { if (otherContainer.getLabel().equals(ruleContext.getLabel())) { continue; } Artifact resourcesJar = createResourceJarArtifact(ruleContext, otherContainer, ".jar"); // combined resource constants copy needs to come before library classes that may contain // their local resource constants attributes.addRuntimeClassPathEntry(resourcesJar); Artifact jarJarRuleFile = createResourceJarArtifact( ruleContext, otherContainer, ".jar_jarjar_rules.txt"); String jarJarRule = String.format("rule %s.* %s.@1", originalPackage, otherContainer.getJavaPackage()); ruleContext.registerAction(new FileWriteAction( ruleContext.getActionOwner(), jarJarRuleFile, jarJarRule, false)); FilesToRunProvider jarjar = ruleContext.getExecutablePrerequisite("$jarjar_bin", Mode.HOST); ruleContext.registerAction(new SpawnAction.Builder() .setExecutable(jarjar) .addArgument("process") .addInputArgument(jarJarRuleFile) .addInputArgument(binaryResourcesJar) .addOutputArgument(resourcesJar) .setProgressMessage("Repackaging jar") .setMnemonic("AndroidRepackageJar") .build(ruleContext)); } } private static Artifact createResourceJarArtifact(RuleContext ruleContext, ResourceContainer container, String fileNameSuffix) { String artifactName = container.getLabel().getName() + fileNameSuffix; // Since the Java sources are generated by combining all resources with the // ones included in the binary, the path of the artifact has to be unique // per binary and per library (not only per library). Artifact artifact = ruleContext.getUniqueDirectoryArtifact("resource_jars", container.getLabel().getPackageIdentifier().getPathFragment().getRelative(artifactName), ruleContext.getBinOrGenfilesDirectory()); return artifact; } public JavaTargetAttributes init( JavaSemantics javaSemantics, AndroidSemantics androidSemantics, ResourceApk resourceApk, boolean addCoverageSupport, boolean collectJavaCompilationArgs) throws InterruptedException { classJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_CLASS_JAR); idlHelper = new AndroidIdlHelper(ruleContext, classJar); ImmutableList.Builder extraSourcesBuilder = ImmutableList.builder() .addAll(resourceApk.isLegacy() || resourceApk.getResourceJavaSrcJar() == null ? ImmutableList.of() : ImmutableList.of(resourceApk.getResourceJavaSrcJar())) .addAll(idlHelper.getIdlGeneratedJavaSources()); JavaTargetAttributes.Builder attributes = init( androidSemantics, resourceApk.getTransitiveResources(), extraSourcesBuilder.build()); JavaCompilationArtifacts.Builder artifactsBuilder = new JavaCompilationArtifacts.Builder(); if (resourceApk.isLegacy()) { compileResources(javaSemantics, artifactsBuilder, attributes, resourceApk.getTransitiveResources(), resourceApk.getPrimaryResource()); } JavaCompilationHelper helper = initAttributes(attributes, javaSemantics); if (ruleContext.hasErrors()) { return null; } if (addCoverageSupport) { androidSemantics.addCoverageSupport(ruleContext, this, javaSemantics, true, attributes, artifactsBuilder); if (ruleContext.hasErrors()) { return null; } } jackCompilationHelper = initJack(helper.getAttributes(), javaSemantics); if (ruleContext.hasErrors()) { return null; } initJava( helper, artifactsBuilder, collectJavaCompilationArgs, resourceApk.getResourceJavaSrcJar()); if (ruleContext.hasErrors()) { return null; } return helper.getAttributes(); } private JavaTargetAttributes.Builder init( AndroidSemantics androidSemantics, NestedSet transitiveResources, Collection extraArtifacts) { this.transitiveResources = transitiveResources; javaCommon.initializeJavacOpts(androidSemantics.getJavacArguments()); JavaTargetAttributes.Builder attributes = javaCommon.initCommon(extraArtifacts); attributes.setBootClassPath(ImmutableList.of( AndroidSdkProvider.fromRuleContext(ruleContext).getAndroidJar())); return attributes; } private JavaCompilationHelper initAttributes( JavaTargetAttributes.Builder attributes, JavaSemantics semantics) { JavaCompilationHelper helper = new JavaCompilationHelper( ruleContext, semantics, javaCommon.getJavacOpts(), attributes); Iterable deps = javaCommon.targetsTreatedAsDeps(ClasspathType.BOTH); helper.addLibrariesToAttributes(deps); helper.addProvidersToAttributes(javaCommon.compilationArgsFromSources(), asNeverLink); attributes.setStrictJavaDeps(getStrictAndroidDeps()); attributes.setRuleKind(ruleContext.getRule().getRuleClass()); attributes.setTargetLabel(ruleContext.getLabel()); JavaCommon.validateConstraint(ruleContext, "android", deps); ruleContext.checkSrcsSamePackage(true); return helper; } private StrictDepsMode getStrictAndroidDeps() { // Get command line strict_android_deps option StrictDepsMode strict = ruleContext.getFragment(AndroidConfiguration.class).getStrictDeps(); // Use option if anything but DEFAULT, which is now equivalent to ERROR. return (strict != DEFAULT && strict != STRICT) ? strict : ERROR; } JackCompilationHelper initJack(JavaTargetAttributes attributes, JavaSemantics javaSemantics) throws InterruptedException { AndroidSdkProvider sdk = AndroidSdkProvider.fromRuleContext(ruleContext); return new JackCompilationHelper.Builder() // blaze infrastructure .setRuleContext(ruleContext) // configuration .setOutputArtifact( ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_JACK_FILE)) // tools .setAndroidSdk(sdk) // sources .addJavaSources(attributes.getSourceFiles()) .addSourceJars(attributes.getSourceJars()) .addCompiledJars(attributes.getJarFiles()) .addResources(attributes.getResources()) .addProcessorNames(attributes.getProcessorNames()) .addProcessorClasspathJars(attributes.getProcessorPath()) .addExports(JavaCommon.getExports(ruleContext)) .addClasspathDeps(javaCommon.targetsTreatedAsDeps(ClasspathType.COMPILE_ONLY)) .addRuntimeDeps(javaCommon.targetsTreatedAsDeps(ClasspathType.RUNTIME_ONLY)) .build(); } private void initJava( JavaCompilationHelper helper, JavaCompilationArtifacts.Builder javaArtifactsBuilder, boolean collectJavaCompilationArgs, @Nullable Artifact additionalSourceJar) throws InterruptedException { NestedSetBuilder filesBuilder = NestedSetBuilder.stableOrder(); if (additionalSourceJar != null) { filesBuilder.add(additionalSourceJar); } JavaTargetAttributes attributes = helper.getAttributes(); if (ruleContext.hasErrors()) { // Avoid leaving filesToBuild set to null, otherwise we'll get a NullPointerException masking // the real error. filesToBuild = filesBuilder.build(); return; } if (attributes.hasJarFiles()) { // This rule is repackaging some source jars as a java library javaArtifactsBuilder.addRuntimeJars(attributes.getJarFiles()); javaArtifactsBuilder.addCompileTimeJars(attributes.getCompileTimeJarFiles()); filesBuilder.addAll(attributes.getJarFiles()); } Artifact jar = null; if (attributes.hasSourceFiles() || attributes.hasSourceJars() || attributes.hasResources()) { // We only want to add a jar to the classpath of a dependent rule if it has content. javaArtifactsBuilder.addRuntimeJar(classJar); jar = classJar; } filesBuilder.add(classJar); manifestProtoOutput = helper.createManifestProtoOutput(classJar); // The gensrc jar is created only if the target uses annotation processing. Otherwise, // it is null, and the source jar action will not depend on the compile action. if (helper.usesAnnotationProcessing()) { genClassJar = helper.createGenJar(classJar); genSourceJar = helper.createGensrcJar(classJar); helper.createGenJarAction(classJar, manifestProtoOutput, genClassJar); } srcJar = ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_LIBRARY_SOURCE_JAR); helper.createSourceJarAction(srcJar, genSourceJar); NestedSetBuilder compileTimeDependenciesBuilder = NestedSetBuilder.stableOrder(); Artifact outputDepsProto = helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder); if (outputDepsProto != null) { compileTimeDependenciesBuilder.add(outputDepsProto); } helper.createCompileActionWithInstrumentation(classJar, manifestProtoOutput, genSourceJar, outputDepsProto, javaArtifactsBuilder); compileTimeDependencyArtifacts = compileTimeDependenciesBuilder.build(); filesToBuild = filesBuilder.build(); if ((attributes.hasSourceFiles() || attributes.hasSourceJars()) && jar != null) { iJar = helper.createCompileTimeJarAction(jar, outputDepsProto, javaArtifactsBuilder); } javaCommon.setJavaCompilationArtifacts(javaArtifactsBuilder.build()); javaCommon.setClassPathFragment( new ClasspathConfiguredFragment( javaCommon.getJavaCompilationArtifacts(), attributes, asNeverLink)); transitiveNeverlinkLibraries = collectTransitiveNeverlinkLibraries( ruleContext, javaCommon.getDependencies(), javaCommon.getJavaCompilationArtifacts().getRuntimeJars()); topLevelSourceJars = ImmutableList.of(srcJar); transitiveSourceJars = javaCommon.collectTransitiveSourceJars(srcJar); boolean hasSources = attributes.hasSourceFiles() || attributes.hasSourceJars(); if (!hasSources) { // If this android rule has no sources, then it's a forwarding rule, so also forward // any exported java plugins from its deps. this.transitiveJavaPluginInfoProvider = JavaPluginInfoProvider.merge( javaCommon.getPluginInfoProvidersForAttribute("deps", Mode.TARGET)); } if (collectJavaCompilationArgs) { this.javaCompilationArgs = collectJavaCompilationArgs(ruleContext, exportDeps, asNeverLink, hasSources); this.recursiveJavaCompilationArgs = collectJavaCompilationArgs( ruleContext, true, asNeverLink, /* hasSources */ true); } } public RuleConfiguredTargetBuilder addTransitiveInfoProviders( RuleConfiguredTargetBuilder builder, AndroidSemantics androidSemantics, ResourceApk resourceApk, Artifact zipAlignedApk, Iterable apksUnderTest) { Runfiles runfiles = new Runfiles.Builder(ruleContext.getWorkspaceName()) .addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES) .build(); javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar); javaCommon.addGenJarsProvider(builder, genClassJar, genSourceJar); idlHelper.addTransitiveInfoProviders(builder, classJar, manifestProtoOutput); return builder .setFilesToBuild(filesToBuild) .add(JavaRuleOutputJarsProvider.class, new JavaRuleOutputJarsProvider( classJar, iJar, srcJar)) .add( JavaRuntimeJarProvider.class, new JavaRuntimeJarProvider(javaCommon.getJavaCompilationArtifacts().getRuntimeJars())) .add(RunfilesProvider.class, RunfilesProvider.simple(runfiles)) .add( AndroidResourcesProvider.class, new AndroidResourcesProvider(ruleContext.getLabel(), transitiveResources)) .add( AndroidIdeInfoProvider.class, createAndroidIdeInfoProvider(ruleContext, androidSemantics, idlHelper, resourceApk, zipAlignedApk, apksUnderTest)) .add( JavaCompilationArgsProvider.class, new JavaCompilationArgsProvider( javaCompilationArgs, recursiveJavaCompilationArgs, compileTimeDependencyArtifacts, NestedSetBuilder.emptySet(Order.STABLE_ORDER))) .add( JackLibraryProvider.class, asNeverLink ? jackCompilationHelper.compileAsNeverlinkLibrary() : jackCompilationHelper.compileAsLibrary()) .add(JavaPluginInfoProvider.class, transitiveJavaPluginInfoProvider) .addOutputGroup( OutputGroupProvider.HIDDEN_TOP_LEVEL, collectHiddenTopLevelArtifacts(ruleContext)) .addOutputGroup(JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, transitiveSourceJars); } public static PathFragment getAssetDir(RuleContext ruleContext) { return new PathFragment(ruleContext.attributes().get( AndroidResourcesProvider.ResourceType.ASSETS.getAttribute() + "_dir", Type.STRING)); } public static NestedSet collectTransitiveNativeLibraries( Iterable deps) { NestedSetBuilder builder = NestedSetBuilder.stableOrder(); for (TransitiveInfoCollection dep : deps) { AndroidNativeLibraryProvider android = dep.getProvider(AndroidNativeLibraryProvider.class); if (android != null) { builder.addTransitive(android.getTransitiveAndroidNativeLibraries()); continue; } JavaNativeLibraryProvider java = dep.getProvider(JavaNativeLibraryProvider.class); if (java != null) { builder.addTransitive(java.getTransitiveJavaNativeLibraries()); continue; } CcNativeLibraryProvider cc = dep.getProvider(CcNativeLibraryProvider.class); if (cc != null) { for (LinkerInput input : cc.getTransitiveCcNativeLibraries()) { Artifact library = input.getOriginalLibraryArtifact(); String name = library.getFilename(); if (CppFileTypes.SHARED_LIBRARY.matches(name) || CppFileTypes.VERSIONED_SHARED_LIBRARY.matches(name)) { builder.add(input); } } continue; } } return builder.build(); } public static AndroidResourcesProvider getAndroidResources(RuleContext ruleContext) { if (!ruleContext.attributes().has("resources", BuildType.LABEL)) { return null; } TransitiveInfoCollection prerequisite = ruleContext.getPrerequisite("resources", Mode.TARGET); if (prerequisite == null) { return null; } return prerequisite.getProvider(AndroidResourcesProvider.class); } public static NestedSet getApplicationApks(RuleContext ruleContext) { NestedSetBuilder applicationApksBuilder = NestedSetBuilder.stableOrder(); for (ApkProvider dep : ruleContext.getPrerequisites("deps", Mode.TARGET, ApkProvider.class)) { applicationApksBuilder.addTransitive(dep.getTransitiveApks()); } return applicationApksBuilder.build(); } private JavaCompilationArgs collectJavaCompilationArgs(RuleContext ruleContext, boolean recursive, boolean neverLink, boolean hasSrcs) { JavaCompilationArgs.Builder builder = JavaCompilationArgs.builder() .merge(javaCommon.getJavaCompilationArtifacts(), neverLink); if (recursive || !hasSrcs) { builder.addTransitiveTargets(ruleContext.getPrerequisites("deps", Mode.TARGET), recursive, neverLink ? ClasspathType.COMPILE_ONLY : ClasspathType.BOTH); } return builder.build(); } public ImmutableList getJavacOpts() { return javaCommon.getJavacOpts(); } public Artifact getGenClassJar() { return genClassJar; } @Nullable public Artifact getGenSourceJar() { return genSourceJar; } public ImmutableList getRuntimeJars() { return javaCommon.getJavaCompilationArtifacts().getRuntimeJars(); } public Artifact getInstrumentedJar() { return javaCommon.getJavaCompilationArtifacts().getInstrumentedJar(); } public NestedSet getTransitiveNeverLinkLibraries() { return transitiveNeverlinkLibraries; } public Iterable getTopLevelSourceJars() { return topLevelSourceJars; } public NestedSet getTransitiveSourceJars() { return transitiveSourceJars; } public JavaSourceJarsProvider getJavaSourceJarsProvider() { return new JavaSourceJarsProvider(getTransitiveSourceJars(), getTopLevelSourceJars()); } public boolean isNeverLink() { return asNeverLink; } public CcLinkParamsStore getCcLinkParamsStore() { return getCcLinkParamsStore(javaCommon.targetsTreatedAsDeps(ClasspathType.BOTH)); } public static CcLinkParamsStore getCcLinkParamsStore( final Iterable deps) { return new CcLinkParamsStore() { @Override protected void collect(CcLinkParams.Builder builder, boolean linkingStatically, boolean linkShared) { builder.addTransitiveTargets(deps, // Link in Java-specific C++ code in the transitive closure JavaCcLinkParamsProvider.TO_LINK_PARAMS, // Link in Android-specific C++ code (e.g., android_libraries) in the transitive closure AndroidCcLinkParamsProvider.TO_LINK_PARAMS, // Link in non-language-specific C++ code in the transitive closure CcLinkParamsProvider.TO_LINK_PARAMS); } }; } private NestedSet collectHiddenTopLevelArtifacts(RuleContext ruleContext) { NestedSetBuilder builder = NestedSetBuilder.stableOrder(); for (OutputGroupProvider provider : ruleContext.getPrerequisites("deps", Mode.TARGET, OutputGroupProvider.class)) { builder.addTransitive(provider.getOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL)); } return builder.build(); } }