@Override
  public <A extends Arg> JavaTest createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args)
      throws NoSuchBuildTargetException {
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    JavacOptions javacOptions =
        JavacOptionsFactory.create(templateJavacOptions, params, resolver, pathResolver, args);

    CxxLibraryEnhancement cxxLibraryEnhancement =
        new CxxLibraryEnhancement(
            params, args.useCxxLibraries, resolver, pathResolver, cxxPlatform);
    params = cxxLibraryEnhancement.updatedParams;

    BuildTarget abiJarTarget = params.getBuildTarget().withAppendedFlavors(CalculateAbi.FLAVOR);

    JavaTest test =
        resolver.addToIndex(
            new JavaTest(
                params.appendExtraDeps(
                    Iterables.concat(
                        BuildRules.getExportedRules(
                            Iterables.concat(
                                params.getDeclaredDeps().get(),
                                resolver.getAllRules(args.providedDeps.get()))),
                        pathResolver.filterBuildRuleInputs(javacOptions.getInputs(pathResolver)))),
                pathResolver,
                args.srcs.get(),
                ResourceValidator.validateResources(
                    pathResolver, params.getProjectFilesystem(), args.resources.get()),
                javacOptions.getGeneratedSourceFolderName(),
                args.labels.get(),
                args.contacts.get(),
                args.proguardConfig.transform(
                    SourcePaths.toSourcePath(params.getProjectFilesystem())),
                new BuildTargetSourcePath(abiJarTarget),
                javacOptions.trackClassUsage(),
                /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
                args.testType.or(TestType.JUNIT),
                new JavacToJarStepFactory(javacOptions, JavacOptionsAmender.IDENTITY),
                javaOptions.getJavaRuntimeLauncher(),
                args.vmArgs.get(),
                cxxLibraryEnhancement.nativeLibsEnvironment,
                validateAndGetSourcesUnderTest(
                    args.sourceUnderTest.get(), params.getBuildTarget(), resolver),
                args.resourcesRoot,
                args.mavenCoords,
                args.testRuleTimeoutMs.or(defaultTestRuleTimeoutMs),
                args.env.get(),
                args.getRunTestSeparately(),
                args.stdOutLogLevel,
                args.stdErrLogLevel));

    resolver.addToIndex(
        CalculateAbi.of(
            abiJarTarget, pathResolver, params, new BuildTargetSourcePath(test.getBuildTarget())));

    return test;
  }
  public static CxxHeaderSourceSpec requireLexYaccSources(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      ImmutableMap<String, SourcePath> lexSources,
      ImmutableMap<String, SourcePath> yaccSources) {
    BuildTarget lexYaccTarget = createLexYaccSourcesBuildTarget(params.getBuildTarget());

    // Check the cache...
    Optional<BuildRule> rule = ruleResolver.getRuleOptional(lexYaccTarget);
    if (rule.isPresent()) {
      @SuppressWarnings("unchecked")
      ContainerBuildRule<CxxHeaderSourceSpec> containerRule =
          (ContainerBuildRule<CxxHeaderSourceSpec>) rule.get();
      return containerRule.get();
    }

    // Setup the rules to run lex/yacc.
    CxxHeaderSourceSpec lexYaccSources =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            ruleResolver,
            cxxPlatform,
            ImmutableList.<String>of(),
            lexSources,
            ImmutableList.<String>of(),
            yaccSources);

    ruleResolver.addToIndex(
        ContainerBuildRule.of(params, pathResolver, lexYaccTarget, lexYaccSources));

    return lexYaccSources;
  }
  @Test
  public void ruleKeyDoesNotChangeWhenOnlyDependencyRuleKeyChanges() throws Exception {
    ProjectFilesystem filesystem = new FakeProjectFilesystem();
    BuildRuleResolver resolver =
        new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    Path depOutput = Paths.get("output");
    FakeBuildRule dep =
        resolver.addToIndex(
            new FakeBuildRule(BuildTargetFactory.newInstance("//:dep"), filesystem, pathResolver));
    dep.setOutputFile(depOutput.toString());
    filesystem.writeContentsToPath("hello", dep.getPathToOutput());

    FakeFileHashCache hashCache =
        new FakeFileHashCache(ImmutableMap.of(filesystem.resolve(depOutput), HashCode.fromInt(0)));

    BuildRule rule =
        GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:rule"))
            .setOut("out")
            .setSrcs(ImmutableList.<SourcePath>of(new BuildTargetSourcePath(dep.getBuildTarget())))
            .build(resolver, filesystem);

    RuleKey inputKey1 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule);

    RuleKey inputKey2 = new InputBasedRuleKeyBuilderFactory(0, hashCache, pathResolver).build(rule);

    assertThat(inputKey1, Matchers.equalTo(inputKey2));
  }
示例#4
0
  @Test
  public void shouldSetInputsFromSourcePaths() {
    ExportFileBuilder builder =
        ExportFileBuilder.newExportFileBuilder(target)
            .setSrc(new TestSourcePath("chips"))
            .setOut("cake");

    ExportFile exportFile = (ExportFile) builder.build(new BuildRuleResolver());

    assertIterablesEquals(singleton(Paths.get("chips")), exportFile.getSource());

    BuildRuleResolver ruleResolver = new BuildRuleResolver();
    FakeBuildRule rule =
        ruleResolver.addToIndex(
            new FakeBuildRule(
                BuildTargetFactory.newInstance("//example:one"),
                new SourcePathResolver(ruleResolver)));

    builder.setSrc(new BuildTargetSourcePath(rule.getBuildTarget()));
    exportFile = (ExportFile) builder.build(ruleResolver);
    assertTrue(Iterables.isEmpty(exportFile.getSource()));

    builder.setSrc(null);
    exportFile = (ExportFile) builder.build(new BuildRuleResolver());
    assertIterablesEquals(singleton(Paths.get("example.html")), exportFile.getSource());
  }
  /**
   * There was a bug where `BuildTargetSourcePath` sources were written to the classes file using
   * their string representation, rather than their resolved path.
   */
  @Test
  public void shouldWriteResolvedBuildTargetSourcePathsToClassesFile()
      throws IOException, InterruptedException {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    BuildRule rule = new FakeBuildRule("//:fake", pathResolver);
    resolver.addToIndex(rule);

    Jsr199Javac javac = createJavac(/* withSyntaxError */ false);
    ExecutionContext executionContext = TestExecutionContext.newInstance();
    int exitCode =
        javac.buildWithClasspath(
            executionContext,
            createProjectFilesystem(),
            PATH_RESOLVER,
            BuildTargetFactory.newInstance("//some:example"),
            ImmutableList.<String>of(),
            SOURCE_PATHS,
            Optional.of(pathToSrcsList),
            Optional.<Path>absent());
    assertEquals("javac should exit with code 0.", exitCode, 0);

    File srcsListFile = pathToSrcsList.toFile();
    assertTrue(srcsListFile.exists());
    assertTrue(srcsListFile.isFile());
    assertEquals("Example.java", Files.toString(srcsListFile, Charsets.UTF_8).trim());
  }
  @Test
  public void ruleKeyDoesNotChangeWhenOnlyDependencyRuleKeyChanges() {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    Path depOutput = Paths.get("output");
    FakeBuildRule dep =
        resolver.addToIndex(
            new FakeBuildRule(BuildTargetFactory.newInstance("//:dep"), pathResolver));
    dep.setOutputFile(depOutput.toString());

    FakeFileHashCache hashCache =
        new FakeFileHashCache(ImmutableMap.of(depOutput, HashCode.fromInt(0)));

    BuildRule rule = new FakeAbiRuleBuildRule("//:rule", pathResolver, dep);

    dep.setRuleKey(new RuleKey("aaaa"));
    RuleKey inputKey1 =
        new AbiRuleKeyBuilderFactory(hashCache, pathResolver).newInstance(rule).build();

    dep.setRuleKey(new RuleKey("bbbb"));
    RuleKey inputKey2 =
        new AbiRuleKeyBuilderFactory(hashCache, pathResolver).newInstance(rule).build();

    assertThat(inputKey1, equalTo(inputKey2));
  }
示例#7
0
  @Test
  public void testGetExecutableCommand() {
    BuildRuleResolver ruleResolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

    // prebuilt_jar //third_party/generator:generator
    PrebuiltJarBuilder.createBuilder(
            BuildTargetFactory.newInstance("//third_party/generator:generator"))
        .setBinaryJar(PATH_TO_GENERATOR_JAR)
        .build(ruleResolver);

    // prebuilt_jar //third_party/guava:guava
    BuildRule guava =
        PrebuiltJarBuilder.createBuilder(
                BuildTargetFactory.newInstance("//third_party/guava:guava"))
            .setBinaryJar(PATH_TO_GUAVA_JAR)
            .build(ruleResolver);

    // java_library //java/com/facebook/base:base
    BuildRule libraryRule =
        JavaLibraryBuilder.createBuilder(
                BuildTargetFactory.newInstance("//java/com/facebook/base:base"))
            .addSrc(Paths.get("java/com/facebook/base/Base.java"))
            .addDep(guava.getBuildTarget())
            .build(ruleResolver);

    BuildRuleParams params =
        new FakeBuildRuleParamsBuilder(
                BuildTargetFactory.newInstance("//java/com/facebook/base:Main"))
            .setDeps(ImmutableSortedSet.of(libraryRule))
            .build();
    // java_binary //java/com/facebook/base:Main
    JavaBinary javaBinary =
        ruleResolver.addToIndex(
            new JavaBinary(
                params,
                new SourcePathResolver(ruleResolver),
                "com.facebook.base.Main",
                null,
                /* merge manifests */ true,
                null,
                /* blacklist */ ImmutableSet.<String>of(),
                new DefaultDirectoryTraverser(),
                ImmutableSetMultimap.<JavaLibrary, Path>of()));

    // Strip the trailing "." from the absolute path to the current directory.
    final String basePath = new File(".").getAbsolutePath().replaceFirst("\\.$", "");

    // Each classpath entry is specified via its absolute path so that the executable command can be
    // run from a /tmp directory, if necessary.
    String expectedClasspath = basePath + javaBinary.getPathToOutput();

    List<String> expectedCommand = ImmutableList.of("java", "-jar", expectedClasspath);
    assertEquals(expectedCommand, javaBinary.getExecutableCommand().getCommandPrefix(pathResolver));

    assertFalse(
        "Library rules that are used exclusively by genrules should not be part of the classpath.",
        expectedClasspath.contains(PATH_TO_GENERATOR_JAR.toString()));
  }
  private ImmutableList<SourcePath> generateCCompilation(ImmutableList<SourcePath> cInput) {

    ImmutableList.Builder<SourcePath> objects = ImmutableList.builder();

    ImmutableList.Builder<String> cCompileFlags = ImmutableList.builder();
    cCompileFlags.addAll(ocamlContext.getCCompileFlags());
    cCompileFlags.addAll(ocamlContext.getCommonCFlags());

    CxxPreprocessorInput cxxPreprocessorInput = ocamlContext.getCxxPreprocessorInput();

    for (SourcePath cSrc : cInput) {
      String name = pathResolver.getAbsolutePath(cSrc).toFile().getName();
      BuildTarget target = createCCompileBuildTarget(params.getBuildTarget(), name);

      BuildRuleParams cCompileParams =
          params.copyWithChanges(
              target,
              /* declaredDeps */ Suppliers.ofInstance(
                  ImmutableSortedSet.<BuildRule>naturalOrder()
                      // Depend on the rule that generates the sources and headers we're compiling.
                      .addAll(
                          pathResolver.filterBuildRuleInputs(
                              ImmutableList.<SourcePath>builder()
                                  .add(cSrc)
                                  .addAll(
                                      cxxPreprocessorInput
                                          .getIncludes()
                                          .getNameToPathMap()
                                          .values())
                                  .build()))
                      // Also add in extra deps from the preprocessor input, such as the symlink
                      // tree rules.
                      .addAll(
                          BuildRules.toBuildRulesFor(
                              params.getBuildTarget(), resolver, cxxPreprocessorInput.getRules()))
                      .addAll(params.getDeclaredDeps().get())
                      .build()),
              /* extraDeps */ params.getExtraDeps());

      Path outputPath = ocamlContext.getCOutput(pathResolver.getRelativePath(cSrc));
      OCamlCCompile compileRule =
          new OCamlCCompile(
              cCompileParams,
              pathResolver,
              new OCamlCCompileStep.Args(
                  cCompiler.getEnvironment(pathResolver),
                  cCompiler.getCommandPrefix(pathResolver),
                  ocamlContext.getOcamlCompiler().get(),
                  outputPath,
                  cSrc,
                  cCompileFlags.build(),
                  ImmutableMap.copyOf(cxxPreprocessorInput.getIncludes().getNameToPathMap())));
      resolver.addToIndex(compileRule);
      objects.add(new BuildTargetSourcePath(compileRule.getBuildTarget()));
    }
    return objects.build();
  }
 private BuildRule buildRuleAndAddToIndex(
     Buildable buildable,
     BuildRuleType buildRuleType,
     BuildTarget buildTarget,
     ImmutableSortedSet<BuildRule> deps) {
   BuildRule buildRule =
       Buildables.createRuleFromBuildable(
           buildable, buildRuleType, buildTarget, deps, buildRuleParams);
   ruleResolver.addToIndex(buildTarget, buildRule);
   return buildRule;
 }
  @Test
  public void createBuildRuleForUnflavoredTargetCreateThriftLibrary() {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift");
    BuildRuleParams unflavoredParams =
        BuildRuleParamsFactory.createTrivialBuildRuleParams(unflavoredTarget);

    // Setup an empty thrift buck config, missing the compiler.
    FakeBuckConfig buckConfig =
        new FakeBuckConfig(
            ImmutableMap.<String, ImmutableMap<String, String>>of(),
            ImmutableMap.<String, String>of());
    ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig);
    ThriftLibraryDescription desc =
        new ThriftLibraryDescription(
            thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of());

    // Setup the thrift source.
    String sourceName = "test.thrift";
    SourcePath source = new TestSourcePath(sourceName);

    // Create a dep and verify it gets attached.
    BuildTarget depTarget = BuildTargetFactory.newInstance("//:dep");
    Path depIncludeRoot = desc.getIncludeRoot(depTarget);
    HeaderSymlinkTree depIncludeSymlinkTree =
        createFakeSymlinkTree(depTarget, pathResolver, depIncludeRoot);
    ThriftLibrary dep =
        new ThriftLibrary(
            BuildRuleParamsFactory.createTrivialBuildRuleParams(depTarget),
            pathResolver,
            ImmutableSortedSet.<ThriftLibrary>of(),
            depIncludeSymlinkTree,
            ImmutableMap.<Path, SourcePath>of());
    resolver.addToIndex(dep);

    // Build up the constructor arg.
    ThriftConstructorArg arg = desc.createUnpopulatedConstructorArg();
    arg.name = "thrift";
    arg.srcs = ImmutableMap.of(source, ImmutableList.<String>of());
    arg.deps = Optional.of(ImmutableSortedSet.of(dep.getBuildTarget()));
    arg.flags = Optional.absent();

    // Build the thrift library rule and verify that it's setup correctly.
    BuildRule rule = desc.createBuildRule(TargetGraph.EMPTY, unflavoredParams, resolver, arg);
    assertTrue(rule instanceof ThriftLibrary);
    ThriftLibrary me = (ThriftLibrary) rule;
    assertEquals(ImmutableSortedSet.of(dep), me.getThriftDeps());
    assertEquals(desc.getIncludeRoot(unflavoredTarget), me.getIncludeTreeRule().getIncludePath());
  }
 /**
  * Ensure that the build rule generated by the given {@link BuildRuleParams} had been generated by
  * it's corresponding {@link Description} and added to the {@link BuildRuleResolver}. If not, call
  * into it's associated {@link Description} to generate it's {@link BuildRule}.
  *
  * @return the {@link BuildRule} generated by the description corresponding to the supplied {@link
  *     BuildRuleParams}.
  */
 public static BuildRule requireBuildRule(
     TargetGraph targetGraph,
     BuildRuleParams params,
     BuildRuleResolver ruleResolver,
     Flavor... flavors) {
   BuildTarget target = BuildTarget.builder(params.getBuildTarget()).addFlavors(flavors).build();
   Optional<BuildRule> rule = ruleResolver.getRuleOptional(target);
   if (!rule.isPresent()) {
     TargetNode<?> node = targetGraph.get(params.getBuildTarget());
     Preconditions.checkNotNull(
         node, String.format("%s not in target graph", params.getBuildTarget()));
     rule = Optional.of(createBuildRule(targetGraph, params, ruleResolver, node, flavors));
     ruleResolver.addToIndex(rule.get());
   }
   return rule.get();
 }
  private BuildRule generateBytecodeLinking(ImmutableList<SourcePath> allInputs) {
    BuildRuleParams linkParams =
        params.copyWithChanges(
            addBytecodeFlavor(params.getBuildTarget()),
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>naturalOrder()
                    .addAll(pathResolver.filterBuildRuleInputs(allInputs))
                    .addAll(ocamlContext.getBytecodeLinkDeps())
                    .addAll(
                        FluentIterable.from(ocamlContext.getLinkableInput().getArgs())
                            .append(ocamlContext.getNativeLinkableInput().getArgs())
                            .transformAndConcat(Arg.getDepsFunction(pathResolver))
                            .filter(Predicates.not(Predicates.instanceOf(OCamlBuild.class))))
                    .build()),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    ImmutableList<String> linkerInputs =
        FluentIterable.from(allInputs)
            .transform(pathResolver.deprecatedPathFunction())
            .transform(Functions.toStringFunction())
            .toList();

    ImmutableList.Builder<String> flags = ImmutableList.builder();
    flags.addAll(ocamlContext.getFlags());
    flags.addAll(ocamlContext.getCommonCLinkerFlags());

    OCamlLink link =
        new OCamlLink(
            linkParams,
            pathResolver,
            allInputs,
            new OCamlLinkStep.Args(
                cxxCompiler.getEnvironment(pathResolver),
                cxxCompiler.getCommandPrefix(pathResolver),
                ocamlContext.getOcamlBytecodeCompiler().get(),
                ocamlContext.getBytecodeOutput(),
                ocamlContext.getLinkableInput().getArgs(),
                ocamlContext.getNativeLinkableInput().getArgs(),
                linkerInputs,
                flags.build(),
                ocamlContext.isLibrary(),
                /* isBytecode */ true));
    resolver.addToIndex(link);
    return link;
  }
  @Test
  public void shouldUseSpecifiedJavacJar() throws Exception {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    BuildRule rule = new FakeBuildRule("//:fake", pathResolver);
    resolver.addToIndex(rule);

    Path fakeJavacJar = Paths.get("ae036e57-77a7-4356-a79c-0f85b1a3290d", "fakeJavac.jar");
    ExecutionContext executionContext = TestExecutionContext.newInstance();
    MockClassLoader mockClassLoader =
        new MockClassLoader(
            ClassLoader.getSystemClassLoader(),
            ImmutableMap.<String, Class<?>>of(
                "com.sun.tools.javac.api.JavacTool", MockJavac.class));
    executionContext
        .getClassLoaderCache()
        .injectClassLoader(
            ClassLoader.getSystemClassLoader(),
            ImmutableList.of(fakeJavacJar.toUri().toURL()),
            mockClassLoader);

    Jsr199Javac javac = createJavac(/* withSyntaxError */ false, Optional.of(fakeJavacJar));

    boolean caught = false;

    try {
      javac.buildWithClasspath(
          executionContext,
          createProjectFilesystem(),
          PATH_RESOLVER,
          BuildTargetFactory.newInstance("//some:example"),
          ImmutableList.<String>of(),
          SOURCE_PATHS,
          Optional.of(pathToSrcsList),
          Optional.<Path>absent());
      fail("Did not expect compilation to succeed");
    } catch (UnsupportedOperationException ex) {
      if (ex.toString().contains("abcdef")) {
        caught = true;
      }
    }

    assertTrue("mock Java compiler should throw", caught);
  }
  private BuildRule generateDebugLauncherRule() {
    BuildRuleParams debugParams =
        params.copyWithChanges(
            addDebugFlavor(params.getBuildTarget()),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    OCamlDebugLauncher debugLauncher =
        new OCamlDebugLauncher(
            debugParams,
            pathResolver,
            new OCamlDebugLauncherStep.Args(
                ocamlContext.getOcamlDebug().get(),
                ocamlContext.getBytecodeOutput(),
                ocamlContext.getOCamlInput(),
                ocamlContext.getBytecodeIncludeFlags()));
    resolver.addToIndex(debugLauncher);
    return debugLauncher;
  }
示例#15
0
  @Test
  public void testCreateWorkerToolWithBadExeValue() throws NoSuchBuildTargetException {
    BuildRuleResolver resolver =
        new BuildRuleResolver(TargetGraph.EMPTY, new DefaultTargetNodeToBuildRuleTransformer());

    BuildRule nonBinaryBuildRule =
        new FakeBuildRule(
            BuildTargetFactory.newInstance("//:fake"), new SourcePathResolver(resolver));
    resolver.addToIndex(nonBinaryBuildRule);

    BuildTarget workerTarget = BuildTargetFactory.newInstance("//:worker_rule");
    try {
      WorkerToolBuilder.newWorkerToolBuilder(workerTarget)
          .setExe(nonBinaryBuildRule.getBuildTarget())
          .build(resolver);
    } catch (HumanReadableException e) {
      assertThat(
          e.getHumanReadableErrorMessage(),
          Matchers.containsString("needs to correspond to a binary rule"));
    }
  }
示例#16
0
  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {
    BuildTarget libraryTarget =
        BuildTarget.builder(params.getBuildTarget())
            .addFlavors(ImmutableFlavor.of("compile"))
            .build();
    GoLibrary library =
        GoDescriptors.createGoLibraryRule(
            params.copyWithBuildTarget(libraryTarget),
            resolver,
            goBuckConfig,
            Paths.get("main"),
            args.srcs,
            args.compilerFlags.or(ImmutableList.<String>of()));
    resolver.addToIndex(library);

    BuildRuleParams binaryParams =
        params.copyWithDeps(
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(library)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    GoSymlinkTree symlinkTree =
        GoDescriptors.requireTransitiveSymlinkTreeRule(binaryParams, resolver);

    return new GoBinary(
        params.copyWithDeps(
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(symlinkTree, library)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
        new SourcePathResolver(resolver),
        cxxPlatform.getLd(),
        symlinkTree,
        library,
        goBuckConfig.getGoLinker().get(),
        ImmutableList.<String>builder()
            .addAll(goBuckConfig.getLinkerFlags())
            .addAll(args.linkerFlags.or(ImmutableList.<String>of()))
            .build());
  }
示例#17
0
 public JavaTest build(BuildRuleResolver resolver) {
   BuildRuleParams params =
       new FakeBuildRuleParamsBuilder(target)
           .setType(JavaTestDescription.TYPE)
           .setDeps(deps.build())
           .build();
   JavaTest test =
       new JavaTest(
           params,
           srcs.build(),
           resources.build(),
           labels.build(),
           contacts.build(),
           proguardConfig,
           /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
           JavacOptions.DEFAULTS,
           vmArgs,
           sourcesUnderTest.build(),
           Optional.<Path>absent());
   resolver.addToIndex(test);
   return test;
 }
  public static HeaderSymlinkTree requireHeaderSymlinkTree(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      boolean includeLexYaccHeaders,
      ImmutableMap<String, SourcePath> lexSources,
      ImmutableMap<String, SourcePath> yaccSources,
      ImmutableMap<Path, SourcePath> headers,
      HeaderVisibility headerVisibility) {
    BuildTarget headerSymlinkTreeTarget =
        CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
            params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility);

    // Check the cache...
    Optional<BuildRule> rule = ruleResolver.getRuleOptional(headerSymlinkTreeTarget);
    if (rule.isPresent()) {
      Preconditions.checkState(rule.get() instanceof HeaderSymlinkTree);
      return (HeaderSymlinkTree) rule.get();
    }

    HeaderSymlinkTree symlinkTree =
        createHeaderSymlinkTree(
            params,
            ruleResolver,
            pathResolver,
            cxxPlatform,
            includeLexYaccHeaders,
            lexSources,
            yaccSources,
            headers,
            headerVisibility);

    ruleResolver.addToIndex(symlinkTree);

    return symlinkTree;
  }
  @Test
  public void createBuildRuleWithFlavoredTargetCallsEnhancerCorrectly() throws IOException {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    FakeProjectFilesystem filesystem = new FakeProjectFilesystem();

    // Setup the default values returned by the language specific enhancer.
    String language = "fake";
    Flavor flavor = ImmutableFlavor.of("fake");
    final BuildRule implicitDep = createFakeBuildRule("//implicit:dep", pathResolver);
    resolver.addToIndex(implicitDep);
    filesystem.mkdirs(implicitDep.getBuildTarget().getBasePath());
    filesystem.touch(implicitDep.getBuildTarget().getBasePath().resolve("BUCK"));
    ImmutableSet<BuildTarget> implicitDeps = ImmutableSet.of(implicitDep.getBuildTarget());
    ImmutableSet<String> options = ImmutableSet.of();

    // Create the build targets and params.
    BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift");
    BuildRuleParams unflavoredParams =
        new FakeBuildRuleParamsBuilder(unflavoredTarget).setProjectFilesystem(filesystem).build();
    BuildTarget flavoredTarget =
        BuildTargets.createFlavoredBuildTarget(unflavoredTarget.checkUnflavored(), flavor);
    BuildRuleParams flavoredParams =
        new FakeBuildRuleParamsBuilder(flavoredTarget).setProjectFilesystem(filesystem).build();

    // Setup a thrift source file generated by a genrule.
    final String thriftSourceName1 = "foo.thrift";
    BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule");
    final Genrule genrule =
        (Genrule)
            GenruleBuilder.newGenruleBuilder(genruleTarget)
                .setOut(thriftSourceName1)
                .build(resolver);
    SourcePath thriftSource1 = new BuildTargetSourcePath(genrule.getBuildTarget());
    final ImmutableList<String> thriftServices1 = ImmutableList.of();

    // Setup a normal thrift source file.
    final String thriftSourceName2 = "bar.thrift";
    SourcePath thriftSource2 = new TestSourcePath(thriftSourceName2);
    final ImmutableList<String> thriftServices2 = ImmutableList.of();

    // Create a build rule that represents the thrift rule.
    final FakeBuildRule thriftRule = createFakeBuildRule("//thrift:target", pathResolver);
    resolver.addToIndex(thriftRule);
    filesystem.mkdirs(thriftRule.getBuildTarget().getBasePath());
    filesystem.touch(thriftRule.getBuildTarget().getBasePath().resolve("BUCK"));

    // Setup a simple description with an empty config.
    FakeBuckConfig buckConfig =
        new FakeBuckConfig(
            ImmutableMap.of(
                "thrift", ImmutableMap.of("compiler", thriftRule.getBuildTarget().toString())));
    ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig);
    ThriftLibraryDescription desc =
        new ThriftLibraryDescription(
            thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of());

    // Setup the include rules.
    final BuildRule thriftIncludeSymlinkTree =
        createFakeBuildRule(
            desc.createThriftIncludeSymlinkTreeTarget(unflavoredTarget), pathResolver);

    // Setup our language enhancer
    FakeThriftLanguageSpecificEnhancer enhancer =
        new FakeThriftLanguageSpecificEnhancer(language, flavor, implicitDeps, options) {
          @Override
          public void checkCreateBuildRuleInputs(
              ImmutableMap<String, ThriftSource> sources, ImmutableSortedSet<BuildRule> deps) {

            // Verify both thrift sources are present in the list.
            assertEquals(2, sources.size());
            ThriftSource src1 = sources.get(thriftSourceName1);
            assertNotNull(src1);
            ThriftSource src2 = sources.get(thriftSourceName2);
            assertNotNull(src2);

            // Verify the services are listed correctly for both sources.
            assertEquals(thriftServices1, src1.getServices());
            assertEquals(thriftServices2, src2.getServices());

            // Verify dependencies are setup correctly.
            assertEquals(
                ImmutableSortedSet.of(genrule, thriftRule, thriftIncludeSymlinkTree),
                src1.getCompileRule().getDeps());
            assertEquals(
                ImmutableSortedSet.of(genrule, thriftRule, thriftIncludeSymlinkTree),
                src2.getCompileRule().getDeps());

            // Verify the language specific implicit rules are added correctly.
            assertEquals(
                ImmutableSortedSet.<BuildRule>naturalOrder().add(implicitDep).build(), deps);
          }
        };

    // Recreate the description with the enhancer we setup above.
    desc =
        new ThriftLibraryDescription(
            thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of(enhancer));

    // Setup the internal structure indicating that the thrift target was set in the
    // buck config.
    // desc.setCompilerTarget(thriftRule.getBuildTarget());

    // Setup the implicit deps for the flavored build target.
    // desc.setImplicitDeps(flavoredTarget, ImmutableList.of(implicitDep.getBuildTarget()));

    // Build up the constructor arg.
    ThriftConstructorArg arg = desc.createUnpopulatedConstructorArg();
    arg.name = "thrift";
    arg.srcs =
        ImmutableMap.of(
            thriftSource1, thriftServices1,
            thriftSource2, thriftServices2);
    arg.deps = Optional.absent();
    arg.flags = Optional.absent();

    // Setup the unflavored target, which should just produce a ThriftInclude, SymlinkTree, and
    // ThriftLibrary rule.
    BuildRule rule = desc.createBuildRule(TargetGraph.EMPTY, unflavoredParams, resolver, arg);
    resolver.addToIndex(rule);

    // Now attempt to create the flavored thrift library.
    desc.createBuildRule(TargetGraph.EMPTY, flavoredParams, resolver, arg);
  }
  /**
   * Generate {@link Lex} and {@link Yacc} rules generating C/C++ sources from the given lex/yacc
   * sources.
   *
   * @return {@link CxxHeaderSourceSpec} containing the generated headers/sources
   */
  public static CxxHeaderSourceSpec createLexYaccBuildRules(
      BuildRuleParams params,
      BuildRuleResolver resolver,
      CxxPlatform cxxPlatform,
      ImmutableList<String> lexFlags,
      ImmutableMap<String, SourcePath> lexSrcs,
      ImmutableList<String> yaccFlags,
      ImmutableMap<String, SourcePath> yaccSrcs) {
    if (!lexSrcs.isEmpty() && !cxxPlatform.getLex().isPresent()) {
      throw new HumanReadableException(
          "Platform %s must support lex to compile srcs %s", cxxPlatform, lexSrcs);
    }

    if (!yaccSrcs.isEmpty() && !cxxPlatform.getYacc().isPresent()) {
      throw new HumanReadableException(
          "Platform %s must support yacc to compile srcs %s", cxxPlatform, yaccSrcs);
    }

    SourcePathResolver pathResolver = new SourcePathResolver(resolver);

    ImmutableMap.Builder<String, CxxSource> lexYaccCxxSourcesBuilder = ImmutableMap.builder();
    ImmutableMap.Builder<Path, SourcePath> lexYaccHeadersBuilder = ImmutableMap.builder();

    // Loop over all lex sources, generating build rule for each one and adding the sources
    // and headers it generates to our bookkeeping maps.
    UnflavoredBuildTarget unflavoredBuildTarget =
        params.getBuildTarget().getUnflavoredBuildTarget();
    for (ImmutableMap.Entry<String, SourcePath> ent : lexSrcs.entrySet()) {
      final String name = ent.getKey();
      final SourcePath source = ent.getValue();

      BuildTarget target = createLexBuildTarget(unflavoredBuildTarget, name);
      Path outputSource = getLexSourceOutputPath(unflavoredBuildTarget, name);
      Path outputHeader = getLexHeaderOutputPath(unflavoredBuildTarget, name);

      // Create the build rule to run lex on this source and add it to the resolver.
      Lex lex =
          new Lex(
              params.copyWithChanges(
                  target,
                  Suppliers.ofInstance(
                      ImmutableSortedSet.copyOf(
                          pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))),
                  Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
              pathResolver,
              cxxPlatform.getLex().get(),
              ImmutableList.<String>builder()
                  .addAll(cxxPlatform.getLexFlags())
                  .addAll(lexFlags)
                  .build(),
              outputSource,
              outputHeader,
              source);
      resolver.addToIndex(lex);

      // Record the output source and header as {@link BuildRuleSourcePath} objects.
      lexYaccCxxSourcesBuilder.put(
          name + ".cc",
          CxxSource.of(
              CxxSource.Type.CXX,
              new BuildTargetSourcePath(lex.getBuildTarget(), outputSource),
              ImmutableList.<String>of()));
      lexYaccHeadersBuilder.put(
          params.getBuildTarget().getBasePath().resolve(name + ".h"),
          new BuildTargetSourcePath(lex.getBuildTarget(), outputHeader));
    }

    // Loop over all yaccc sources, generating build rule for each one and adding the sources
    // and headers it generates to our bookkeeping maps.
    for (ImmutableMap.Entry<String, SourcePath> ent : yaccSrcs.entrySet()) {
      final String name = ent.getKey();
      final SourcePath source = ent.getValue();

      BuildTarget target = createYaccBuildTarget(unflavoredBuildTarget, name);
      Path outputPrefix =
          getYaccOutputPrefix(unflavoredBuildTarget, Files.getNameWithoutExtension(name));

      // Create the build rule to run yacc on this source and add it to the resolver.
      Yacc yacc =
          new Yacc(
              params.copyWithChanges(
                  target,
                  Suppliers.ofInstance(
                      ImmutableSortedSet.copyOf(
                          pathResolver.filterBuildRuleInputs(ImmutableList.of(source)))),
                  Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
              pathResolver,
              cxxPlatform.getYacc().get(),
              ImmutableList.<String>builder()
                  .addAll(cxxPlatform.getYaccFlags())
                  .addAll(yaccFlags)
                  .build(),
              outputPrefix,
              source);
      resolver.addToIndex(yacc);

      // Record the output source and header as {@link BuildRuleSourcePath} objects.
      lexYaccCxxSourcesBuilder.put(
          name + ".cc",
          CxxSource.of(
              CxxSource.Type.CXX,
              new BuildTargetSourcePath(
                  yacc.getBuildTarget(), Yacc.getSourceOutputPath(outputPrefix)),
              ImmutableList.<String>of()));

      lexYaccHeadersBuilder.put(
          params.getBuildTarget().getBasePath().resolve(name + ".h"),
          new BuildTargetSourcePath(yacc.getBuildTarget(), Yacc.getHeaderOutputPath(outputPrefix)));
    }

    return CxxHeaderSourceSpec.of(lexYaccHeadersBuilder.build(), lexYaccCxxSourcesBuilder.build());
  }
  @Test
  public void createThriftCompilerBuildRulesHasCorrectDeps() throws IOException {
    BuildRuleResolver resolver = new BuildRuleResolver();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    FakeProjectFilesystem filesystem = new FakeProjectFilesystem();

    String language = "fake";
    Flavor flavor = ImmutableFlavor.of("fake");
    ImmutableSet<String> options = ImmutableSet.of();

    // Setup the default values returned by the language specific enhancer.
    BuildTarget unflavoredTarget = BuildTargetFactory.newInstance("//:thrift");
    BuildRuleParams unflavoredParams =
        new FakeBuildRuleParamsBuilder(BuildTarget.builder(unflavoredTarget).build())
            .setProjectFilesystem(filesystem)
            .build();

    // Setup a thrift source file generated by a genrule.
    BuildTarget flavoredTarget =
        BuildTargets.createFlavoredBuildTarget(unflavoredTarget.checkUnflavored(), flavor);
    BuildRuleParams flavoredParams =
        new FakeBuildRuleParamsBuilder(flavoredTarget).setProjectFilesystem(filesystem).build();

    // Create a path for the thrift compiler.
    Path thriftPath = Paths.get("thrift_path");
    filesystem.touch(thriftPath);

    // Setup an thrift buck config, with the path to the thrift compiler set.
    FakeBuckConfig buckConfig =
        new FakeBuckConfig(
            ImmutableMap.of("thrift", ImmutableMap.of("compiler", thriftPath.toString())),
            filesystem);
    ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(buckConfig);
    ThriftLibraryDescription desc =
        new ThriftLibraryDescription(
            thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of());

    // Setup a simple thrift source.
    String sourceName = "test.thrift";
    SourcePath sourcePath = new TestSourcePath(sourceName);

    // Generate these rules using no deps.
    ImmutableMap<String, ThriftCompiler> rules =
        desc.createThriftCompilerBuildRules(
            flavoredParams,
            resolver,
            ThriftLibraryDescription.CompilerType.THRIFT,
            ImmutableList.<String>of(),
            language,
            options,
            ImmutableMap.of(sourceName, sourcePath),
            ImmutableSortedSet.<ThriftLibrary>of());

    // Now verify that the generated rule had no associated deps.
    assertSame(rules.size(), 1);
    ThriftCompiler rule = rules.get(sourceName);
    assertNotNull(rule);
    assertEquals(ImmutableSortedSet.<BuildRule>of(), rule.getDeps());

    // Lets do this again, but pass in a ThriftLibrary deps, wrapping some includes we need.
    Path includeRoot = desc.getIncludeRoot(unflavoredTarget);
    HeaderSymlinkTree thriftIncludeSymlinkTree =
        createFakeSymlinkTree(
            desc.createThriftIncludeSymlinkTreeTarget(unflavoredTarget), pathResolver, includeRoot);
    ThriftLibrary lib =
        new ThriftLibrary(
            unflavoredParams,
            pathResolver,
            ImmutableSortedSet.<ThriftLibrary>of(),
            thriftIncludeSymlinkTree,
            ImmutableMap.<Path, SourcePath>of());

    // Generate these rules using no deps.
    rules =
        desc.createThriftCompilerBuildRules(
            flavoredParams,
            resolver,
            ThriftLibraryDescription.CompilerType.THRIFT,
            ImmutableList.<String>of(),
            language,
            options,
            ImmutableMap.of(sourceName, sourcePath),
            ImmutableSortedSet.of(lib));

    // Now verify that the generated rule has all the deps from the passed in thrift library.
    assertSame(rules.size(), 1);
    rule = rules.get(sourceName);
    assertNotNull(rule);
    assertEquals(ImmutableSortedSet.<BuildRule>of(thriftIncludeSymlinkTree), rule.getDeps());

    // Setup a simple genrule that creates the thrift source and verify its dep is propagated.
    Genrule genrule =
        (Genrule)
            GenruleBuilder.newGenruleBuilder(BuildTargetFactory.newInstance("//:genrule"))
                .setOut(sourceName)
                .build(resolver);
    SourcePath ruleSourcePath = new BuildTargetSourcePath(genrule.getBuildTarget());

    // Generate these rules using no deps and the genrule generated source.
    rules =
        desc.createThriftCompilerBuildRules(
            flavoredParams,
            resolver,
            ThriftLibraryDescription.CompilerType.THRIFT,
            ImmutableList.<String>of(),
            language,
            options,
            ImmutableMap.of(sourceName, ruleSourcePath),
            ImmutableSortedSet.<ThriftLibrary>of());

    // Now verify that the generated rule had no associated deps.
    assertSame(rules.size(), 1);
    rule = rules.get(sourceName);
    assertNotNull(rule);
    assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), rule.getDeps());

    // Create a build rule that represents the thrift rule.
    FakeBuildRule thriftRule = createFakeBuildRule("//thrift:target", pathResolver);
    resolver.addToIndex(thriftRule);
    filesystem.mkdirs(thriftRule.getBuildTarget().getBasePath());
    filesystem.touch(thriftRule.getBuildTarget().getBasePath().resolve("BUCK"));

    // Setup an empty thrift buck config, and set compiler target.
    buckConfig =
        new FakeBuckConfig(
            ImmutableMap.of(
                "thrift", ImmutableMap.of("compiler", thriftRule.getBuildTarget().toString())),
            filesystem);
    thriftBuckConfig = new ThriftBuckConfig(buckConfig);
    desc =
        new ThriftLibraryDescription(
            thriftBuckConfig, ImmutableList.<ThriftLanguageSpecificEnhancer>of());

    // Generate these rules using no deps with a compiler target.
    rules =
        desc.createThriftCompilerBuildRules(
            flavoredParams,
            resolver,
            ThriftLibraryDescription.CompilerType.THRIFT,
            ImmutableList.<String>of(),
            language,
            options,
            ImmutableMap.of(sourceName, sourcePath),
            ImmutableSortedSet.<ThriftLibrary>of());

    // Now verify that the generated rule only has deps from the compiler target.
    assertSame(rules.size(), 1);
    rule = rules.get(sourceName);
    assertNotNull(rule);
    assertEquals(ImmutableSortedSet.<BuildRule>of(thriftRule), rule.getDeps());
  }
  /**
   * Creates/finds the set of build rules that correspond to pre-dex'd artifacts that should be
   * merged to create the final classes.dex for the APK.
   *
   * <p>This method may modify {@code ruleResolver}, inserting new rules into its index.
   */
  @VisibleForTesting
  PreDexMerge createPreDexMergeRule(
      AaptPackageResources aaptPackageResources,
      Iterable<DexProducedFromJavaLibrary> preDexRulesNotInThePackageableCollection,
      AndroidPackageableCollection packageableCollection) {
    ImmutableSortedSet.Builder<JavaLibrary> javaLibraryDepsBuilder =
        ImmutableSortedSet.naturalOrder();
    ImmutableSet.Builder<DexProducedFromJavaLibrary> preDexDeps = ImmutableSet.builder();
    preDexDeps.addAll(preDexRulesNotInThePackageableCollection);
    for (BuildTarget buildTarget : packageableCollection.getJavaLibrariesToDex()) {
      Preconditions.checkState(
          !buildTargetsToExcludeFromDex.contains(buildTarget),
          "JavaLibrary should have been excluded from target to dex: %s",
          buildTarget);

      BuildRule libraryRule = ruleResolver.getRule(buildTarget);

      // Skip uber R.java since AaptPackageResources takes care of dexing.
      if (libraryRule.equals(aaptPackageResources)) {
        continue;
      }

      Preconditions.checkState(libraryRule instanceof JavaLibrary);
      JavaLibrary javaLibrary = (JavaLibrary) libraryRule;

      // If the rule has no output file (which happens when a java_library has no srcs or
      // resources, but export_deps is true), then there will not be anything to dx.
      if (javaLibrary.getPathToOutput() == null) {
        continue;
      }

      // Take note of the rule so we add it to the enhanced deps.
      javaLibraryDepsBuilder.add(javaLibrary);

      // See whether the corresponding IntermediateDexRule has already been added to the
      // ruleResolver.
      BuildTarget originalTarget = javaLibrary.getBuildTarget();
      BuildTarget preDexTarget = BuildTarget.builder(originalTarget).addFlavors(DEX_FLAVOR).build();
      Optional<BuildRule> preDexRule = ruleResolver.getRuleOptional(preDexTarget);
      if (preDexRule.isPresent()) {
        preDexDeps.add((DexProducedFromJavaLibrary) preDexRule.get());
        continue;
      }

      // Create the IntermediateDexRule and add it to both the ruleResolver and preDexDeps.
      BuildRuleParams paramsForPreDex =
          buildRuleParams.copyWithChanges(
              preDexTarget,
              Suppliers.ofInstance(
                  ImmutableSortedSet.of(ruleResolver.getRule(javaLibrary.getBuildTarget()))),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      DexProducedFromJavaLibrary preDex =
          new DexProducedFromJavaLibrary(paramsForPreDex, pathResolver, javaLibrary);
      ruleResolver.addToIndex(preDex);
      preDexDeps.add(preDex);
    }

    ImmutableSet<DexProducedFromJavaLibrary> allPreDexDeps = preDexDeps.build();

    BuildRuleParams paramsForPreDexMerge =
        buildRuleParams.copyWithChanges(
            createBuildTargetWithFlavor(DEX_MERGE_FLAVOR),
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>naturalOrder()
                    .addAll(getDexMergeDeps(aaptPackageResources, allPreDexDeps))
                    .addAll(javaLibraryDepsBuilder.build())
                    .build()),
            /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
    PreDexMerge preDexMerge =
        new PreDexMerge(
            paramsForPreDexMerge,
            pathResolver,
            primaryDexPath,
            dexSplitMode,
            allPreDexDeps,
            aaptPackageResources,
            dxExecutorService,
            xzCompressionLevel);
    ruleResolver.addToIndex(preDexMerge);

    return preDexMerge;
  }
示例#23
0
  @Override
  public <A extends Args> BuildRule createBuildRule(
      TargetGraph targetGraph, BuildRuleParams params, BuildRuleResolver resolver, A args) {

    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    ImmutableMap<String, SourcePath> nativeLibraries =
        JavaLibraryRules.getNativeLibraries(targetGraph, params.getDeps(), cxxPlatform);
    BuildRuleParams binaryParams = params;

    // If we're packaging native libraries, we'll build the binary JAR in a separate rule and
    // package it into the final fat JAR, so adjust it's params to use a flavored target.
    if (!nativeLibraries.isEmpty()) {
      binaryParams =
          params.copyWithChanges(
              BuildTarget.builder(params.getBuildTarget())
                  .addFlavors(FAT_JAR_INNER_JAR_FLAVOR)
                  .build(),
              params.getDeclaredDeps(),
              params.getExtraDeps());
    }

    // Construct the build rule to build the binary JAR.
    ImmutableSetMultimap<JavaLibrary, Path> transitiveClasspathEntries =
        Classpaths.getClasspathEntries(binaryParams.getDeps());
    BuildRule rule =
        new JavaBinary(
            binaryParams.appendExtraDeps(transitiveClasspathEntries.keys()),
            pathResolver,
            args.mainClass.orNull(),
            args.manifestFile.orNull(),
            args.mergeManifests.or(true),
            args.metaInfDirectory.orNull(),
            args.blacklist.or(ImmutableSortedSet.<String>of()),
            new DefaultDirectoryTraverser(),
            transitiveClasspathEntries,
            javaBinOverride);

    // If we're packaging native libraries, construct the rule to build the fat JAR, which packages
    // up the original binary JAR and any required native libraries.
    if (!nativeLibraries.isEmpty()) {
      BuildRule innerJarRule = rule;
      resolver.addToIndex(innerJarRule);
      SourcePath innerJar = new BuildTargetSourcePath(innerJarRule.getBuildTarget());
      rule =
          new JarFattener(
              params.appendExtraDeps(
                  Suppliers.<Iterable<BuildRule>>ofInstance(
                      pathResolver.filterBuildRuleInputs(
                          ImmutableList.<SourcePath>builder()
                              .add(innerJar)
                              .addAll(nativeLibraries.values())
                              .build()))),
              pathResolver,
              javacOptions,
              innerJar,
              nativeLibraries,
              javaBinOverride);
    }

    return rule;
  }
  private void generateSingleMLBytecodeCompilation(
      Map<Path, ImmutableSortedSet<BuildRule>> sourceToRule,
      ImmutableList.Builder<SourcePath> cmoFiles,
      Path mlSource,
      ImmutableMap<Path, ImmutableList<Path>> sources,
      ImmutableList<Path> cycleDetector) {

    ImmutableList<Path> newCycleDetector =
        ImmutableList.<Path>builder().addAll(cycleDetector).add(mlSource).build();

    if (cycleDetector.contains(mlSource)) {
      throw new HumanReadableException(
          "Dependency cycle detected: %s", Joiner.on(" -> ").join(newCycleDetector));
    }
    if (sourceToRule.containsKey(mlSource)) {
      return;
    }

    ImmutableSortedSet.Builder<BuildRule> depsBuilder = ImmutableSortedSet.naturalOrder();
    if (sources.containsKey(mlSource)) {
      for (Path dep : checkNotNull(sources.get(mlSource))) {
        generateSingleMLBytecodeCompilation(sourceToRule, cmoFiles, dep, sources, newCycleDetector);
        depsBuilder.addAll(checkNotNull(sourceToRule.get(dep)));
      }
    }
    ImmutableSortedSet<BuildRule> deps = depsBuilder.build();

    String name = mlSource.toFile().getName();
    BuildTarget buildTarget = createMLBytecodeCompileBuildTarget(params.getBuildTarget(), name);

    BuildRuleParams compileParams =
        params.copyWithChanges(
            buildTarget,
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>naturalOrder()
                    .addAll(params.getDeclaredDeps().get())
                    .addAll(deps)
                    .addAll(ocamlContext.getBytecodeCompileDeps())
                    .build()),
            params.getExtraDeps());

    String outputFileName = getMLBytecodeOutputName(name);
    Path outputPath = ocamlContext.getCompileBytecodeOutputDir().resolve(outputFileName);
    final ImmutableList<String> compileFlags =
        getCompileFlags(/* isBytecode */ true, /* excludeDeps */ false);
    BuildRule compileBytecode =
        new OCamlMLCompile(
            compileParams,
            pathResolver,
            new OCamlMLCompileStep.Args(
                cCompiler.getEnvironment(pathResolver),
                cCompiler.getCommandPrefix(pathResolver),
                ocamlContext.getOcamlBytecodeCompiler().get(),
                outputPath,
                mlSource,
                compileFlags));
    resolver.addToIndex(compileBytecode);
    sourceToRule.put(
        mlSource,
        ImmutableSortedSet.<BuildRule>naturalOrder().add(compileBytecode).addAll(deps).build());
    if (!outputFileName.endsWith(OCamlCompilables.OCAML_CMI)) {
      cmoFiles.add(new BuildTargetSourcePath(compileBytecode.getBuildTarget()));
    }
  }
  /**
   * Creates a rooted DAG of build rules:
   *
   * <ul>
   *   <li>{@code unzip_aar} depends on the deps specified to the original {@code android_aar}
   *   <li>{@code prebuilt_jar} depends on {@code unzip_aar}
   *   <li>{@code android_resource} depends on {@code unzip_aar}
   *   <li>{@code android_library} depends on {@code android_resource}, {@code prebuilt_jar}, and
   *       {@code unzip_aar}
   * </ul>
   *
   * Therefore, the return value is an {link AndroidLibrary} with no {@code srcs}.
   */
  static BuildRule enhance(
      BuildRuleParams originalBuildRuleParams, SourcePath aarFile, BuildRuleResolver ruleResolver) {
    // unzip_aar
    BuildTarget originalBuildTarget = originalBuildRuleParams.getBuildTarget();
    BuildRuleParams unzipAarParams =
        originalBuildRuleParams.copyWithChanges(
            UNZIP_AAR_TYPE,
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_UNZIP_FLAVOR),
            originalBuildRuleParams.getDeclaredDeps(),
            originalBuildRuleParams.getExtraDeps());
    UnzipAar unzipAar = new UnzipAar(unzipAarParams, aarFile);
    ruleResolver.addToIndex(unzipAar);

    // unzip_aar#aar_classes_jar
    BuildRuleParams classesJarParams =
        originalBuildRuleParams.copyWithChanges(
            OutputOnlyBuildRule.TYPE,
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_CLASSES_JAR_FLAVOR),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(unzipAar),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());
    OutputOnlyBuildRule classesJar =
        new OutputOnlyBuildRule(classesJarParams, unzipAar.getPathToClassesJar());
    ruleResolver.addToIndex(classesJar);

    // prebuilt_jar
    BuildRuleParams prebuiltJarParams =
        originalBuildRuleParams.copyWithChanges(
            PrebuiltJarDescription.TYPE,
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_PREBUILT_JAR_FLAVOR),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(unzipAar),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());
    PrebuiltJar prebuiltJar =
        new PrebuiltJar(
            /* params */ prebuiltJarParams,
            new BuildRuleSourcePath(classesJar),
            /* sourceJar */ Optional.<SourcePath>absent(),
            /* gwtJar */ Optional.<SourcePath>absent(),
            /* javadocUrl */ Optional.<String>absent());
    ruleResolver.addToIndex(prebuiltJar);

    // unzip_aar#aar_manifest
    BuildRuleParams manifestParams =
        originalBuildRuleParams.copyWithChanges(
            OutputOnlyBuildRule.TYPE,
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_MANIFEST),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(unzipAar),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());
    OutputOnlyBuildRule manifest =
        new OutputOnlyBuildRule(manifestParams, unzipAar.getAndroidManifest());
    ruleResolver.addToIndex(manifest);

    // android_resource
    BuildRuleParams androidResourceParams =
        originalBuildRuleParams.copyWithChanges(
            AndroidResourceDescription.TYPE,
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ANDROID_RESOURCE_FLAVOR),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(manifest),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());

    // Because all resources and assets are generated files, we specify them as empty collections.
    ImmutableSortedSet<Path> resSrcs = ImmutableSortedSet.of();
    ImmutableSortedSet<Path> assetsSrcs = ImmutableSortedSet.of();

    AndroidResource androidResource =
        new AndroidResource(
            androidResourceParams,
            /* deps */ ImmutableSortedSet.<BuildRule>of(unzipAar),
            unzipAar.getResDirectory(),
            resSrcs,
            /* rDotJavaPackage */ null,
            /* assets */ unzipAar.getAssetsDirectory(),
            assetsSrcs,
            new BuildRuleSourcePath(manifest),
            /* hasWhitelistedStrings */ false);
    ruleResolver.addToIndex(androidResource);

    // android_library
    BuildRuleParams androidLibraryParams =
        originalBuildRuleParams.copyWithChanges(
            AndroidLibraryDescription.TYPE,
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_ANDROID_LIBRARY_FLAVOR),
            /* declaredDeps */ ImmutableSortedSet.<BuildRule>of(
                androidResource, prebuiltJar, unzipAar),
            /* extraDeps */ ImmutableSortedSet.<BuildRule>of());
    return new AndroidLibrary(
        androidLibraryParams,
        /* srcs */ ImmutableSortedSet.<SourcePath>of(),
        /* resources */ ImmutableSortedSet.<SourcePath>of(),
        Optional.of(unzipAar.getProguardConfig()),
        /* postprocessClassesCommands */ ImmutableList.<String>of(),
        /* exportedDeps */ ImmutableSortedSet.<BuildRule>of(prebuiltJar),
        /* providedDeps */ ImmutableSortedSet.<BuildRule>of(),
        /* additionalClasspathEntries */ ImmutableSet.<Path>of(),
        /* javacOptions */ JavacOptions.DEFAULTS,
        /* resourcesRoot */ Optional.<Path>absent(),
        /* manifestFile */ Optional.<SourcePath>absent(),
        /* isPrebuiltAar */ true);
  }
  /**
   * If the user specified any android_build_config() rules, then we must add some build rules to
   * generate the production {@code BuildConfig.class} files and ensure that they are included in
   * the list of {@link AndroidPackageableCollection#getClasspathEntriesToDex}.
   */
  private void addBuildConfigDeps(
      boolean shouldPreDex,
      AndroidPackageableCollection packageableCollection,
      ImmutableSortedSet.Builder<BuildRule> enhancedDeps,
      ImmutableList.Builder<DexProducedFromJavaLibrary> preDexRules,
      ImmutableList.Builder<Path> buildConfigJarFilesBuilder) {
    BuildConfigFields buildConfigConstants =
        BuildConfigFields.fromFields(
            ImmutableList.<BuildConfigFields.Field>of(
                BuildConfigFields.Field.of(
                    "boolean",
                    BuildConfigs.DEBUG_CONSTANT,
                    String.valueOf(packageType != AndroidBinary.PackageType.RELEASE)),
                BuildConfigFields.Field.of(
                    "boolean",
                    BuildConfigs.IS_EXO_CONSTANT,
                    String.valueOf(!exopackageModes.isEmpty())),
                BuildConfigFields.Field.of(
                    "int",
                    BuildConfigs.EXOPACKAGE_FLAGS,
                    String.valueOf(ExopackageMode.toBitmask(exopackageModes)))));
    for (Map.Entry<String, BuildConfigFields> entry :
        packageableCollection.getBuildConfigs().entrySet()) {
      // Merge the user-defined constants with the APK-specific overrides.
      BuildConfigFields totalBuildConfigValues =
          BuildConfigFields.empty()
              .putAll(entry.getValue())
              .putAll(buildConfigValues)
              .putAll(buildConfigConstants);

      // Each enhanced dep needs a unique build target, so we parameterize the build target by the
      // Java package.
      String javaPackage = entry.getKey();
      Flavor flavor = ImmutableFlavor.of("buildconfig_" + javaPackage.replace('.', '_'));
      BuildRuleParams buildConfigParams =
          new BuildRuleParams(
              createBuildTargetWithFlavor(flavor),
              /* declaredDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()),
              buildRuleParams.getProjectFilesystem(),
              buildRuleParams.getRuleKeyBuilderFactory());
      JavaLibrary buildConfigJavaLibrary =
          AndroidBuildConfigDescription.createBuildRule(
              buildConfigParams,
              javaPackage,
              totalBuildConfigValues,
              buildConfigValuesFile,
              /* useConstantExpressions */ true,
              javacOptions,
              ruleResolver);
      ruleResolver.addToIndex(buildConfigJavaLibrary);

      enhancedDeps.add(buildConfigJavaLibrary);
      Path buildConfigJar = buildConfigJavaLibrary.getPathToOutput();
      Preconditions.checkNotNull(
          buildConfigJar, "%s must have an output file.", buildConfigJavaLibrary);
      buildConfigJarFilesBuilder.add(buildConfigJar);

      if (shouldPreDex) {
        DexProducedFromJavaLibrary buildConfigDex =
            new DexProducedFromJavaLibrary(
                buildConfigParams.copyWithChanges(
                    createBuildTargetWithFlavor(ImmutableFlavor.of("dex_" + flavor.getName())),
                    Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of(buildConfigJavaLibrary)),
                    /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of())),
                pathResolver,
                buildConfigJavaLibrary);
        ruleResolver.addToIndex(buildConfigDex);
        enhancedDeps.add(buildConfigDex);
        preDexRules.add(buildConfigDex);
      }
    }
  }
  public static CxxLinkAndCompileRules createBuildRulesForCxxBinary(
      TargetGraph targetGraph,
      BuildRuleParams params,
      BuildRuleResolver resolver,
      CxxPlatform cxxPlatform,
      ImmutableMap<String, CxxSource> srcs,
      ImmutableMap<Path, SourcePath> headers,
      ImmutableMap<String, SourcePath> lexSrcs,
      ImmutableMap<String, SourcePath> yaccSrcs,
      CxxPreprocessMode preprocessMode,
      Linker.LinkableDepType linkStyle,
      Optional<ImmutableList<String>> preprocessorFlags,
      Optional<PatternMatchedCollection<ImmutableList<String>>> platformPreprocessorFlags,
      Optional<ImmutableMap<CxxSource.Type, ImmutableList<String>>> langPreprocessorFlags,
      Optional<ImmutableSortedSet<FrameworkPath>> frameworks,
      Optional<ImmutableList<String>> compilerFlags,
      Optional<PatternMatchedCollection<ImmutableList<String>>> platformCompilerFlags,
      Optional<SourcePath> prefixHeader,
      Optional<ImmutableList<String>> linkerFlags,
      Optional<PatternMatchedCollection<ImmutableList<String>>> platformLinkerFlags,
      Optional<Linker.CxxRuntimeType> cxxRuntimeType) {
    SourcePathResolver sourcePathResolver = new SourcePathResolver(resolver);
    Path linkOutput = getLinkOutputPath(params.getBuildTarget());
    ImmutableList.Builder<Arg> argsBuilder = ImmutableList.builder();
    CommandTool.Builder executableBuilder = new CommandTool.Builder();

    // Setup the rules to run lex/yacc.
    CxxHeaderSourceSpec lexYaccSources =
        requireLexYaccSources(params, resolver, sourcePathResolver, cxxPlatform, lexSrcs, yaccSrcs);

    // Setup the header symlink tree and combine all the preprocessor input from this rule
    // and all dependencies.
    HeaderSymlinkTree headerSymlinkTree =
        requireHeaderSymlinkTree(
            params,
            resolver,
            sourcePathResolver,
            cxxPlatform,
            /* includeLexYaccHeaders */ true,
            lexSrcs,
            yaccSrcs,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        collectCxxPreprocessorInput(
            targetGraph,
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                preprocessorFlags, platformPreprocessorFlags, langPreprocessorFlags, cxxPlatform),
            ImmutableList.of(headerSymlinkTree),
            getFrameworkSearchPaths(frameworks, cxxPlatform, new SourcePathResolver(resolver)),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(
                targetGraph,
                cxxPlatform,
                FluentIterable.from(params.getDeps())
                    .filter(Predicates.instanceOf(CxxPreprocessorDep.class))));

    // The complete list of input sources.
    ImmutableMap<String, CxxSource> sources =
        ImmutableMap.<String, CxxSource>builder()
            .putAll(srcs)
            .putAll(lexYaccSources.getCxxSources())
            .build();

    // Generate and add all the build rules to preprocess and compile the source to the
    // resolver and get the `SourcePath`s representing the generated object files.
    ImmutableMap<CxxPreprocessAndCompile, SourcePath> objects =
        CxxSourceRuleFactory.requirePreprocessAndCompileRules(
            params,
            resolver,
            sourcePathResolver,
            cxxPlatform,
            cxxPreprocessorInput,
            CxxFlags.getFlags(compilerFlags, platformCompilerFlags, cxxPlatform),
            prefixHeader,
            preprocessMode,
            sources,
            linkStyle == Linker.LinkableDepType.STATIC
                ? CxxSourceRuleFactory.PicType.PDC
                : CxxSourceRuleFactory.PicType.PIC);

    // Build up the linker flags, which support macro expansion.
    ImmutableList<String> resolvedLinkerFlags =
        CxxFlags.getFlags(linkerFlags, platformLinkerFlags, cxxPlatform);
    argsBuilder.addAll(
        FluentIterable.from(resolvedLinkerFlags)
            .transform(
                MacroArg.toMacroArgFunction(
                    MACRO_HANDLER,
                    params.getBuildTarget(),
                    params.getCellRoots(),
                    resolver,
                    params.getProjectFilesystem())));

    // Special handling for dynamically linked binaries.
    if (linkStyle == Linker.LinkableDepType.SHARED) {

      // Create a symlink tree with for all shared libraries needed by this binary.
      SymlinkTree sharedLibraries =
          resolver.addToIndex(
              createSharedLibrarySymlinkTree(
                  targetGraph,
                  params,
                  sourcePathResolver,
                  cxxPlatform,
                  Predicates.instanceOf(NativeLinkable.class)));

      // Embed a origin-relative library path into the binary so it can find the shared libraries.
      argsBuilder.addAll(
          StringArg.from(
              Linkers.iXlinker(
                  "-rpath",
                  String.format(
                      "%s/%s",
                      cxxPlatform.getLd().origin(),
                      linkOutput.getParent().relativize(sharedLibraries.getRoot()).toString()))));

      // Add all the shared libraries and the symlink tree as inputs to the tool that represents
      // this binary, so that users can attach the proper deps.
      executableBuilder.addDep(sharedLibraries);
      executableBuilder.addInputs(sharedLibraries.getLinks().values());
    }

    // Add object files into the args.
    argsBuilder.addAll(SourcePathArg.from(sourcePathResolver, objects.values()));

    // Generate the final link rule.  We use the top-level target as the link rule's
    // target, so that it corresponds to the actual binary we build.
    CxxLink cxxLink =
        CxxLinkableEnhancer.createCxxLinkableBuildRule(
            targetGraph,
            cxxPlatform,
            params,
            sourcePathResolver,
            createCxxLinkTarget(params.getBuildTarget()),
            Linker.LinkType.EXECUTABLE,
            Optional.<String>absent(),
            linkOutput,
            argsBuilder.build(),
            linkStyle,
            params.getDeps(),
            cxxRuntimeType,
            Optional.<SourcePath>absent(),
            ImmutableSet.<BuildTarget>of());
    resolver.addToIndex(cxxLink);

    // Add the output of the link as the lone argument needed to invoke this binary as a tool.
    executableBuilder.addArg(new BuildTargetSourcePath(cxxLink.getBuildTarget()));

    return new CxxLinkAndCompileRules(
        cxxLink, ImmutableSortedSet.copyOf(objects.keySet()), executableBuilder.build());
  }
  @Override
  public <A extends Arg> BuildRule createBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams originalBuildRuleParams,
      BuildRuleResolver resolver,
      A args) {

    UnflavoredBuildTarget originalBuildTarget =
        originalBuildRuleParams.getBuildTarget().checkUnflavored();
    SourcePathResolver pathResolver = new SourcePathResolver(resolver);
    ImmutableList.Builder<BuildRule> aarExtraDepsBuilder =
        ImmutableList.<BuildRule>builder().addAll(originalBuildRuleParams.getExtraDeps().get());

    /* android_manifest */
    AndroidManifestDescription.Arg androidManifestArgs =
        androidManifestDescription.createUnpopulatedConstructorArg();
    androidManifestArgs.skeleton = args.manifestSkeleton;
    androidManifestArgs.deps = args.deps;

    BuildRuleParams androidManifestParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ANDROID_MANIFEST_FLAVOR),
            originalBuildRuleParams.getDeclaredDeps(),
            originalBuildRuleParams.getExtraDeps());

    AndroidManifest manifest =
        androidManifestDescription.createBuildRule(
            targetGraph, androidManifestParams, resolver, androidManifestArgs);
    aarExtraDepsBuilder.add(resolver.addToIndex(manifest));

    /* assemble dirs */
    AndroidPackageableCollector collector =
        new AndroidPackageableCollector(
            originalBuildRuleParams.getBuildTarget(),
            /* buildTargetsToExcludeFromDex */ ImmutableSet.<BuildTarget>of(),
            /* resourcesToExclude */ ImmutableSet.<BuildTarget>of());
    collector.addPackageables(
        AndroidPackageableCollector.getPackageableRules(originalBuildRuleParams.getDeps()));
    AndroidPackageableCollection packageableCollection = collector.build();

    ImmutableSortedSet<BuildRule> androidResourceDeclaredDeps =
        AndroidResourceHelper.androidResOnly(originalBuildRuleParams.getDeclaredDeps().get());
    ImmutableSortedSet<BuildRule> androidResourceExtraDeps =
        AndroidResourceHelper.androidResOnly(originalBuildRuleParams.getExtraDeps().get());

    BuildRuleParams assembleAssetsParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(originalBuildTarget, AAR_ASSEMBLE_ASSETS_FLAVOR),
            Suppliers.ofInstance(androidResourceDeclaredDeps),
            Suppliers.ofInstance(androidResourceExtraDeps));
    ImmutableCollection<SourcePath> assetsDirectories =
        packageableCollection.getAssetsDirectories();
    AssembleDirectories assembleAssetsDirectories =
        new AssembleDirectories(assembleAssetsParams, pathResolver, assetsDirectories);
    aarExtraDepsBuilder.add(resolver.addToIndex(assembleAssetsDirectories));

    BuildRuleParams assembleResourceParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ASSEMBLE_RESOURCE_FLAVOR),
            Suppliers.ofInstance(androidResourceDeclaredDeps),
            Suppliers.ofInstance(androidResourceExtraDeps));
    ImmutableCollection<SourcePath> resDirectories =
        packageableCollection.getResourceDetails().getResourceDirectories();
    MergeAndroidResourceSources assembleResourceDirectories =
        new MergeAndroidResourceSources(assembleResourceParams, pathResolver, resDirectories);
    aarExtraDepsBuilder.add(resolver.addToIndex(assembleResourceDirectories));

    /* android_resource */
    BuildRuleParams androidResourceParams =
        originalBuildRuleParams.copyWithChanges(
            BuildTargets.createFlavoredBuildTarget(
                originalBuildTarget, AAR_ANDROID_RESOURCE_FLAVOR),
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>of(
                    manifest, assembleAssetsDirectories, assembleResourceDirectories)),
            Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));

    AndroidResource androidResource =
        new AndroidResource(
            androidResourceParams,
            pathResolver,
            /* deps */ ImmutableSortedSet.<BuildRule>naturalOrder()
                .add(assembleAssetsDirectories)
                .add(assembleResourceDirectories)
                .addAll(originalBuildRuleParams.getDeclaredDeps().get())
                .build(),
            new BuildTargetSourcePath(assembleResourceDirectories.getBuildTarget()),
            /* resSrcs */ ImmutableSortedSet.<SourcePath>of(),
            Optional.<SourcePath>absent(),
            /* rDotJavaPackage */ null,
            new BuildTargetSourcePath(assembleAssetsDirectories.getBuildTarget()),
            /* assetsSrcs */ ImmutableSortedSet.<SourcePath>of(),
            Optional.<SourcePath>absent(),
            new BuildTargetSourcePath(manifest.getBuildTarget()),
            /* hasWhitelistedStrings */ false);
    aarExtraDepsBuilder.add(resolver.addToIndex(androidResource));

    /* native_libraries */
    AndroidNativeLibsPackageableGraphEnhancer packageableGraphEnhancer =
        new AndroidNativeLibsPackageableGraphEnhancer(
            resolver,
            originalBuildRuleParams,
            nativePlatforms,
            ImmutableSet.<NdkCxxPlatforms.TargetCpuType>of());
    Optional<CopyNativeLibraries> nativeLibrariesOptional =
        packageableGraphEnhancer.getCopyNativeLibraries(targetGraph, packageableCollection);
    if (nativeLibrariesOptional.isPresent()) {
      aarExtraDepsBuilder.add(resolver.addToIndex(nativeLibrariesOptional.get()));
    }

    Optional<Path> assembledNativeLibsDir =
        nativeLibrariesOptional.transform(
            new Function<CopyNativeLibraries, Path>() {
              @Override
              public Path apply(CopyNativeLibraries input) {
                return input.getPathToNativeLibsDir();
              }
            });
    BuildRuleParams androidAarParams =
        originalBuildRuleParams.copyWithExtraDeps(
            Suppliers.ofInstance(ImmutableSortedSet.copyOf(aarExtraDepsBuilder.build())));
    return new AndroidAar(
        androidAarParams,
        pathResolver,
        manifest,
        androidResource,
        assembleResourceDirectories.getPathToOutput(),
        assembleAssetsDirectories.getPathToOutput(),
        assembledNativeLibsDir,
        packageableCollection.getNativeLibAssetsDirectories());
  }
  AndroidGraphEnhancementResult createAdditionalBuildables() {
    ImmutableSortedSet.Builder<BuildRule> enhancedDeps = ImmutableSortedSet.naturalOrder();
    enhancedDeps.addAll(originalDeps);

    AndroidPackageableCollector collector =
        new AndroidPackageableCollector(
            originalBuildTarget, buildTargetsToExcludeFromDex, resourcesToExclude);
    collector.addPackageables(AndroidPackageableCollector.getPackageableRules(originalDeps));
    AndroidPackageableCollection packageableCollection = collector.build();
    AndroidPackageableCollection.ResourceDetails resourceDetails =
        packageableCollection.getResourceDetails();

    ImmutableSortedSet<BuildRule> resourceRules =
        getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir());

    FilteredResourcesProvider filteredResourcesProvider;
    boolean needsResourceFiltering =
        resourceFilter.isEnabled()
            || resourceCompressionMode.isStoreStringsAsAssets()
            || !locales.isEmpty();

    if (needsResourceFiltering) {
      BuildRuleParams paramsForResourcesFilter =
          buildRuleParams.copyWithChanges(
              createBuildTargetWithFlavor(RESOURCES_FILTER_FLAVOR),
              Suppliers.ofInstance(
                  ImmutableSortedSet.<BuildRule>naturalOrder()
                      .addAll(resourceRules)
                      .addAll(
                          pathResolver.filterBuildRuleInputs(
                              resourceDetails.getResourceDirectories()))
                      .build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      ResourcesFilter resourcesFilter =
          new ResourcesFilter(
              paramsForResourcesFilter,
              pathResolver,
              resourceDetails.getResourceDirectories(),
              ImmutableSet.copyOf(resourceDetails.getWhitelistedStringDirectories()),
              locales,
              resourceCompressionMode,
              resourceFilter);
      ruleResolver.addToIndex(resourcesFilter);

      filteredResourcesProvider = resourcesFilter;
      enhancedDeps.add(resourcesFilter);
      resourceRules = ImmutableSortedSet.<BuildRule>of(resourcesFilter);
    } else {
      filteredResourcesProvider =
          new IdentityResourcesProvider(
              pathResolver.getAllPaths(resourceDetails.getResourceDirectories()));
    }

    // Create the AaptPackageResourcesBuildable.
    BuildTarget buildTargetForAapt = createBuildTargetWithFlavor(AAPT_PACKAGE_FLAVOR);
    BuildRuleParams paramsForAaptPackageResources =
        buildRuleParams.copyWithChanges(
            buildTargetForAapt,
            Suppliers.ofInstance(
                ImmutableSortedSet.<BuildRule>naturalOrder()
                    // Add all deps with non-empty res dirs, since we at least need the R.txt file
                    // (even if we're filtering).
                    .addAll(getTargetsAsRules(resourceDetails.getResourcesWithNonEmptyResDir()))
                    .addAll(
                        pathResolver.filterBuildRuleInputs(
                            resourceDetails.getResourceDirectories()))
                    .addAll(
                        getAdditionalAaptDeps(pathResolver, resourceRules, packageableCollection))
                    .build()),
            /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
    AaptPackageResources aaptPackageResources =
        new AaptPackageResources(
            paramsForAaptPackageResources,
            pathResolver,
            manifest,
            filteredResourcesProvider,
            getTargetsAsResourceDeps(resourceDetails.getResourcesWithNonEmptyResDir()),
            packageableCollection.getAssetsDirectories(),
            packageType,
            javacOptions,
            shouldPreDex,
            shouldBuildStringSourceMap,
            locales.isEmpty(),
            skipCrunchPngs);
    ruleResolver.addToIndex(aaptPackageResources);
    enhancedDeps.add(aaptPackageResources);

    Optional<PackageStringAssets> packageStringAssets = Optional.absent();
    if (resourceCompressionMode.isStoreStringsAsAssets()) {
      BuildTarget buildTargetForPackageStringAssets =
          createBuildTargetWithFlavor(PACKAGE_STRING_ASSETS_FLAVOR);
      BuildRuleParams paramsForPackageStringAssets =
          buildRuleParams.copyWithChanges(
              buildTargetForPackageStringAssets,
              Suppliers.ofInstance(
                  ImmutableSortedSet.<BuildRule>naturalOrder()
                      .add(aaptPackageResources)
                      // Model the dependency on the presence of res directories, which, in the case
                      // of resource filtering, is cached by the `ResourcesFilter` rule.
                      .addAll(
                          Iterables.filter(
                              ImmutableList.of(filteredResourcesProvider), BuildRule.class))
                      .build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      packageStringAssets =
          Optional.of(
              new PackageStringAssets(
                  paramsForPackageStringAssets,
                  pathResolver,
                  locales,
                  filteredResourcesProvider,
                  aaptPackageResources));
      ruleResolver.addToIndex(packageStringAssets.get());
      enhancedDeps.add(packageStringAssets.get());
    }

    // TODO(natthu): Try to avoid re-building the collection by passing UberRDotJava directly.
    if (packageableCollection.getResourceDetails().hasResources()) {
      collector.addClasspathEntry(
          aaptPackageResources,
          new BuildTargetSourcePath(
              aaptPackageResources.getBuildTarget(),
              aaptPackageResources.getPathToCompiledRDotJavaFiles()));
    }

    // BuildConfig deps should not be added for instrumented APKs because BuildConfig.class has
    // already been added to the APK under test.
    ImmutableList<DexProducedFromJavaLibrary> preDexBuildConfigs;
    ImmutableList<Path> buildConfigJarFiles;
    if (packageType == PackageType.INSTRUMENTED) {
      preDexBuildConfigs = ImmutableList.of();
      buildConfigJarFiles = ImmutableList.of();
    } else {
      ImmutableList.Builder<DexProducedFromJavaLibrary> preDexBuildConfigsBuilder =
          ImmutableList.builder();
      ImmutableList.Builder<Path> buildConfigJarFilesBuilder = ImmutableList.builder();
      addBuildConfigDeps(
          shouldPreDex,
          packageableCollection,
          enhancedDeps,
          preDexBuildConfigsBuilder,
          buildConfigJarFilesBuilder);
      preDexBuildConfigs = preDexBuildConfigsBuilder.build();
      buildConfigJarFiles = buildConfigJarFilesBuilder.build();
    }

    packageableCollection = collector.build();

    Optional<PreDexMerge> preDexMerge = Optional.absent();
    if (shouldPreDex) {
      preDexMerge =
          Optional.of(
              createPreDexMergeRule(
                  aaptPackageResources, preDexBuildConfigs, packageableCollection));
      enhancedDeps.add(preDexMerge.get());
    } else {
      enhancedDeps.addAll(getTargetsAsRules(packageableCollection.getJavaLibrariesToDex()));
    }

    // Add dependencies on all the build rules generating third-party JARs.  This is mainly to
    // correctly capture deps when a prebuilt_jar forwards the output from another build rule.
    enhancedDeps.addAll(
        pathResolver.filterBuildRuleInputs(packageableCollection.getPathsToThirdPartyJars()));

    Optional<CopyNativeLibraries> copyNativeLibraries =
        nativeLibsEnhancer.getCopyNativeLibraries(targetGraph, packageableCollection);
    if (copyNativeLibraries.isPresent()) {
      ruleResolver.addToIndex(copyNativeLibraries.get());
      enhancedDeps.add(copyNativeLibraries.get());
    }

    Optional<ComputeExopackageDepsAbi> computeExopackageDepsAbi = Optional.absent();
    if (!exopackageModes.isEmpty()) {
      BuildRuleParams paramsForComputeExopackageAbi =
          buildRuleParams.copyWithChanges(
              createBuildTargetWithFlavor(CALCULATE_ABI_FLAVOR),
              Suppliers.ofInstance(enhancedDeps.build()),
              /* extraDeps */ Suppliers.ofInstance(ImmutableSortedSet.<BuildRule>of()));
      computeExopackageDepsAbi =
          Optional.of(
              new ComputeExopackageDepsAbi(
                  paramsForComputeExopackageAbi,
                  pathResolver,
                  exopackageModes,
                  packageableCollection,
                  aaptPackageResources,
                  copyNativeLibraries,
                  packageStringAssets,
                  preDexMerge,
                  keystore));
      ruleResolver.addToIndex(computeExopackageDepsAbi.get());
      enhancedDeps.add(computeExopackageDepsAbi.get());
    }

    return AndroidGraphEnhancementResult.builder()
        .setPackageableCollection(packageableCollection)
        .setAaptPackageResources(aaptPackageResources)
        .setCopyNativeLibraries(copyNativeLibraries)
        .setPackageStringAssets(packageStringAssets)
        .setPreDexMerge(preDexMerge)
        .setComputeExopackageDepsAbi(computeExopackageDepsAbi)
        .setClasspathEntriesToDex(
            ImmutableSet.<Path>builder()
                .addAll(pathResolver.getAllPaths(packageableCollection.getClasspathEntriesToDex()))
                .addAll(buildConfigJarFiles)
                .build())
        .setFinalDeps(enhancedDeps.build())
        .build();
  }