public static HeaderSymlinkTree createHeaderSymlinkTree(
      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);
    Path headerSymlinkTreeRoot =
        CxxDescriptionEnhancer.getHeaderSymlinkTreePath(
            params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility);
    Optional<Path> headerMapLocation = Optional.absent();
    if (cxxPlatform.getCpp().supportsHeaderMaps() && cxxPlatform.getCxxpp().supportsHeaderMaps()) {
      headerMapLocation =
          Optional.of(
              getHeaderMapPath(params.getBuildTarget(), cxxPlatform.getFlavor(), headerVisibility));
    }

    CxxHeaderSourceSpec lexYaccSources;
    if (includeLexYaccHeaders) {
      lexYaccSources =
          requireLexYaccSources(
              params, ruleResolver, pathResolver, cxxPlatform, lexSources, yaccSources);
    } else {
      lexYaccSources = CxxHeaderSourceSpec.builder().build();
    }

    return CxxPreprocessables.createHeaderSymlinkTreeBuildRule(
        pathResolver,
        headerSymlinkTreeTarget,
        params,
        headerSymlinkTreeRoot,
        headerMapLocation,
        ImmutableMap.<Path, SourcePath>builder()
            .putAll(headers)
            .putAll(lexYaccSources.getCxxHeaders())
            .build());
  }
  @Test
  public void createLexYaccBuildRules() throws IOException {
    BuildRuleResolver resolver = new BuildRuleResolver();

    // Setup our C++ buck config with the paths to the lex/yacc binaries.
    FakeProjectFilesystem filesystem = new FakeProjectFilesystem();
    Path lexPath = Paths.get("lex");
    filesystem.touch(lexPath);
    Path yaccPath = Paths.get("yacc");
    filesystem.touch(yaccPath);
    BuckConfig buckConfig =
        FakeBuckConfig.builder()
            .setSections(
                ImmutableMap.of(
                    "cxx",
                    ImmutableMap.of(
                        "lex", lexPath.toString(),
                        "yacc", yaccPath.toString())))
            .setFilesystem(filesystem)
            .build();
    CxxPlatform cxxBuckConfig = DefaultCxxPlatforms.build(new CxxBuckConfig(buckConfig));

    // Setup the target name and build params.
    UnflavoredBuildTarget target =
        BuildTargetFactory.newInstance("//:test").getUnflavoredBuildTarget();
    BuildRuleParams params = new FakeBuildRuleParamsBuilder(BuildTarget.of(target)).build();

    // Setup a genrule that generates our lex source.
    String lexSourceName = "test.ll";
    BuildTarget genruleTarget = BuildTargetFactory.newInstance("//:genrule_lex");
    Genrule genrule =
        (Genrule)
            GenruleBuilder.newGenruleBuilder(genruleTarget).setOut(lexSourceName).build(resolver);
    SourcePath lexSource = new BuildTargetSourcePath(genrule.getBuildTarget());

    // Use a regular path for our yacc source.
    String yaccSourceName = "test.yy";
    SourcePath yaccSource = new TestSourcePath(yaccSourceName);

    // Build the rules.
    CxxHeaderSourceSpec actual =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            resolver,
            cxxBuckConfig,
            ImmutableList.<String>of(),
            ImmutableMap.of(lexSourceName, lexSource),
            ImmutableList.<String>of(),
            ImmutableMap.of(yaccSourceName, yaccSource));

    // Grab the generated lex rule and verify it has the genrule as a dep.
    Lex lex =
        (Lex) resolver.getRule(CxxDescriptionEnhancer.createLexBuildTarget(target, lexSourceName));
    assertNotNull(lex);
    assertEquals(ImmutableSortedSet.<BuildRule>of(genrule), lex.getDeps());

    // Grab the generated yacc rule and verify it has no deps.
    Yacc yacc =
        (Yacc)
            resolver.getRule(CxxDescriptionEnhancer.createYaccBuildTarget(target, yaccSourceName));
    assertNotNull(yacc);
    assertEquals(ImmutableSortedSet.<BuildRule>of(), yacc.getDeps());

    // Check the header/source spec is correct.
    Path lexOutputSource = CxxDescriptionEnhancer.getLexSourceOutputPath(target, lexSourceName);
    Path lexOutputHeader = CxxDescriptionEnhancer.getLexHeaderOutputPath(target, lexSourceName);
    Path yaccOutputPrefix =
        CxxDescriptionEnhancer.getYaccOutputPrefix(
            target, Files.getNameWithoutExtension(yaccSourceName));
    Path yaccOutputSource = Yacc.getSourceOutputPath(yaccOutputPrefix);
    Path yaccOutputHeader = Yacc.getHeaderOutputPath(yaccOutputPrefix);
    CxxHeaderSourceSpec expected =
        CxxHeaderSourceSpec.of(
            ImmutableMap.<Path, SourcePath>of(
                target.getBasePath().resolve(lexSourceName + ".h"),
                new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputHeader),
                target.getBasePath().resolve(yaccSourceName + ".h"),
                new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputHeader)),
            ImmutableMap.of(
                lexSourceName + ".cc",
                CxxSource.of(
                    CxxSource.Type.CXX,
                    new BuildTargetSourcePath(lex.getBuildTarget(), lexOutputSource),
                    ImmutableList.<String>of()),
                yaccSourceName + ".cc",
                CxxSource.of(
                    CxxSource.Type.CXX,
                    new BuildTargetSourcePath(yacc.getBuildTarget(), yaccOutputSource),
                    ImmutableList.<String>of())));
    assertEquals(expected, actual);
  }
  private <A extends Arg> BuildRule createExtensionBuildRule(
      TargetGraph targetGraph,
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      CxxPlatform cxxPlatform,
      A args) {
    SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);

    // Extract all C/C++ sources from the constructor arg.
    ImmutableMap<String, CxxSource> srcs =
        CxxDescriptionEnhancer.parseCxxSources(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<Path, SourcePath> headers =
        CxxDescriptionEnhancer.parseHeaders(params, ruleResolver, cxxPlatform, args);
    ImmutableMap<String, SourcePath> lexSrcs =
        CxxDescriptionEnhancer.parseLexSources(params, ruleResolver, args);
    ImmutableMap<String, SourcePath> yaccSrcs =
        CxxDescriptionEnhancer.parseYaccSources(params, ruleResolver, args);

    CxxHeaderSourceSpec lexYaccSources =
        CxxDescriptionEnhancer.createLexYaccBuildRules(
            params,
            ruleResolver,
            cxxPlatform,
            ImmutableList.<String>of(),
            lexSrcs,
            ImmutableList.<String>of(),
            yaccSrcs);

    // Setup the header symlink tree and combine all the preprocessor input from this rule
    // and all dependencies.
    HeaderSymlinkTree headerSymlinkTree =
        CxxDescriptionEnhancer.requireHeaderSymlinkTree(
            params,
            ruleResolver,
            new SourcePathResolver(ruleResolver),
            cxxPlatform,
            /* includeLexYaccHeaders */ true,
            lexSrcs,
            yaccSrcs,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        CxxDescriptionEnhancer.collectCxxPreprocessorInput(
            targetGraph,
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                args.preprocessorFlags,
                args.platformPreprocessorFlags,
                args.langPreprocessorFlags,
                cxxPlatform),
            args.prefixHeaders.get(),
            ImmutableList.of(headerSymlinkTree),
            ImmutableSet.<Path>of(),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(
                targetGraph, cxxPlatform, params.getDeps()));

    ImmutableMap<String, CxxSource> allSources =
        ImmutableMap.<String, CxxSource>builder()
            .putAll(srcs)
            .putAll(lexYaccSources.getCxxSources())
            .build();

    // Generate rule to build the object files.
    ImmutableMap<CxxPreprocessAndCompile, SourcePath> picObjects =
        CxxSourceRuleFactory.requirePreprocessAndCompileRules(
            params,
            ruleResolver,
            pathResolver,
            cxxPlatform,
            cxxPreprocessorInput,
            CxxFlags.getFlags(args.compilerFlags, args.platformCompilerFlags, cxxPlatform),
            cxxBuckConfig.getPreprocessMode(),
            allSources,
            CxxSourceRuleFactory.PicType.PIC);

    // Setup the rules to link the shared library.
    String extensionName = getExtensionName(params.getBuildTarget());
    Path extensionPath = getExtensionPath(params.getBuildTarget(), cxxPlatform.getFlavor());
    return CxxLinkableEnhancer.createCxxLinkableBuildRule(
        targetGraph,
        cxxPlatform,
        params,
        pathResolver,
        /* extraLdFlags */ CxxFlags.getFlags(
            args.linkerFlags, args.platformLinkerFlags, cxxPlatform),
        getExtensionTarget(params.getBuildTarget(), cxxPlatform.getFlavor()),
        Linker.LinkType.SHARED,
        Optional.of(extensionName),
        extensionPath,
        picObjects.values(),
        Linker.LinkableDepType.SHARED,
        params.getDeps(),
        args.cxxRuntimeType,
        Optional.<SourcePath>absent());
  }
  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());
  }
  /**
   * 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());
  }