public BuildRule createBuildRule()

in src/com/facebook/buck/cxx/CxxLibraryFactory.java [87:369]


  public BuildRule createBuildRule(
      TargetGraph targetGraph,
      BuildTarget buildTarget,
      ProjectFilesystem projectFilesystem,
      BuildRuleParams metadataRuleParams,
      ActionGraphBuilder graphBuilder,
      CellPathResolver cellRoots,
      CxxLibraryDescriptionArg args,
      Optional<Linker.LinkableDepType> linkableDepType,
      Optional<SourcePath> bundleLoader,
      ImmutableSet<BuildTarget> blacklist,
      ImmutableSortedSet<BuildTarget> extraDeps,
      CxxLibraryDescription.TransitiveCxxPreprocessorInputFunction
          transitiveCxxPreprocessorInputFunction,
      CxxLibraryDescriptionDelegate delegate) {

    CxxPlatformsProvider cxxPlatformsProvider =
        getCxxPlatformsProvider(buildTarget.getTargetConfiguration());
    Flavor defaultCxxFlavor = cxxPlatformsProvider.getDefaultUnresolvedCxxPlatform().getFlavor();

    // See if we're building a particular "type" and "platform" of this library, and if so, extract
    // them from the flavors attached to the build target.
    Optional<Map.Entry<Flavor, CxxLibraryDescription.Type>> type =
        CxxLibraryDescription.getLibType(buildTarget);
    Optional<CxxPlatform> platform =
        cxxPlatformsProvider
            .getUnresolvedCxxPlatforms()
            .getValue(buildTarget)
            .map(
                unresolved ->
                    unresolved.resolve(graphBuilder, buildTarget.getTargetConfiguration()));
    CxxDeps cxxDeps = CxxDeps.builder().addDeps(args.getCxxDeps()).addDeps(extraDeps).build();

    Supplier<CxxPlatform> cxxPlatformOrDefaultSupplier =
        () ->
            platform.orElse(
                cxxPlatformsProvider
                    .getUnresolvedCxxPlatforms()
                    .getValue(args.getDefaultPlatform().orElse(defaultCxxFlavor))
                    .resolve(graphBuilder, buildTarget.getTargetConfiguration()));

    if (buildTarget.getFlavors().contains(CxxCompilationDatabase.COMPILATION_DATABASE)) {
      CxxPlatform cxxPlatformOrDefault = cxxPlatformOrDefaultSupplier.get();
      Optional<CxxLibraryDescriptionDelegate.ConfiguredDelegate> configuredDelegate =
          delegate.requireDelegate(buildTarget, cxxPlatformOrDefault, graphBuilder);

      // XXX: This needs bundleLoader for tests..
      // TODO(T21900763): We should be using `requireObjects` instead but those would not
      // necessarily be `CxxPreprocessAndCompile` rules (e.g., Swift in `apple_library`).
      ImmutableMap<CxxPreprocessAndCompile, SourcePath> objects =
          requireCxxObjects(
              buildTarget.withoutFlavors(CxxCompilationDatabase.COMPILATION_DATABASE),
              projectFilesystem,
              graphBuilder,
              cellRoots,
              cxxBuckConfig,
              cxxPlatformOrDefault,
              cxxPlatformOrDefault.getPicTypeForSharedLinking(),
              args,
              cxxDeps.get(graphBuilder, cxxPlatformOrDefault),
              transitiveCxxPreprocessorInputFunction,
              configuredDelegate);
      return CxxCompilationDatabase.createCompilationDatabase(
          buildTarget, projectFilesystem, objects.keySet());
    } else if (buildTarget
        .getFlavors()
        .contains(CxxCompilationDatabase.UBER_COMPILATION_DATABASE)) {
      return CxxDescriptionEnhancer.createUberCompilationDatabase(
          platform.isPresent()
              ? buildTarget
              : buildTarget.withAppendedFlavors(args.getDefaultPlatform().orElse(defaultCxxFlavor)),
          projectFilesystem,
          graphBuilder);
    } else if (CxxInferEnhancer.INFER_FLAVOR_DOMAIN.containsAnyOf(buildTarget.getFlavors())) {
      return CxxInferEnhancer.requireInferRule(
          buildTarget,
          projectFilesystem,
          graphBuilder,
          cellRoots,
          cxxBuckConfig,
          cxxPlatformOrDefaultSupplier.get(),
          args,
          inferBuckConfig);
    } else if (type.isPresent() && !platform.isPresent()) {
      BuildTarget untypedBuildTarget = CxxLibraryDescription.getUntypedBuildTarget(buildTarget);
      switch (type.get().getValue()) {
        case EXPORTED_HEADERS:
          Optional<HeaderMode> mode = CxxLibraryDescription.HEADER_MODE.getValue(buildTarget);
          if (mode.isPresent()) {
            return createExportedHeaderSymlinkTreeBuildRule(
                untypedBuildTarget, projectFilesystem, graphBuilder, mode.get(), args);
          }
          break;
          // $CASES-OMITTED$
        default:
      }

    } else if (type.isPresent() && platform.isPresent()) {
      Optional<CxxLibraryDescriptionDelegate.ConfiguredDelegate> configuredDelegate =
          delegate.requireDelegate(buildTarget, platform.get(), graphBuilder);

      // If we *are* building a specific type of this lib, call into the type specific
      // rule builder methods.

      BuildTarget untypedBuildTarget = CxxLibraryDescription.getUntypedBuildTarget(buildTarget);
      switch (type.get().getValue()) {
        case HEADERS:
          return createHeaderSymlinkTreeBuildRule(
              untypedBuildTarget, projectFilesystem, graphBuilder, platform.get(), args);
        case EXPORTED_HEADERS:
          return createExportedPlatformHeaderSymlinkTreeBuildRule(
              untypedBuildTarget, projectFilesystem, graphBuilder, platform.get(), args);
        case SHARED:
          return createSharedLibraryBuildRule(
              untypedBuildTarget,
              projectFilesystem,
              graphBuilder,
              cellRoots,
              cxxBuckConfig,
              platform.get(),
              args,
              cxxDeps.get(graphBuilder, platform.get()),
              Linker.LinkType.SHARED,
              linkableDepType.orElse(Linker.LinkableDepType.SHARED),
              makeLinkableListFilter(args, targetGraph),
              Optional.empty(),
              blacklist,
              transitiveCxxPreprocessorInputFunction,
              configuredDelegate);
        case SHARED_INTERFACE:
          return createSharedLibraryInterface(
              untypedBuildTarget,
              projectFilesystem,
              graphBuilder,
              platform.get(),
              cxxBuckConfig.isIndependentSharedLibraryInterfaces());
        case MACH_O_BUNDLE:
          return createSharedLibraryBuildRule(
              untypedBuildTarget,
              projectFilesystem,
              graphBuilder,
              cellRoots,
              cxxBuckConfig,
              platform.get(),
              args,
              cxxDeps.get(graphBuilder, platform.get()),
              Linker.LinkType.MACH_O_BUNDLE,
              linkableDepType.orElse(Linker.LinkableDepType.SHARED),
              makeLinkableListFilter(args, targetGraph),
              bundleLoader,
              blacklist,
              transitiveCxxPreprocessorInputFunction,
              configuredDelegate);
        case STATIC:
          return createStaticLibraryBuildRule(
              untypedBuildTarget,
              projectFilesystem,
              graphBuilder,
              cellRoots,
              cxxBuckConfig,
              platform.get(),
              args,
              cxxDeps.get(graphBuilder, platform.get()),
              PicType.PDC,
              transitiveCxxPreprocessorInputFunction,
              configuredDelegate);
        case STATIC_PIC:
          return createStaticLibraryBuildRule(
              untypedBuildTarget,
              projectFilesystem,
              graphBuilder,
              cellRoots,
              cxxBuckConfig,
              platform.get(),
              args,
              cxxDeps.get(graphBuilder, platform.get()),
              PicType.PIC,
              transitiveCxxPreprocessorInputFunction,
              configuredDelegate);
      }
      throw new RuntimeException("unhandled library build type");
    }

    boolean hasObjectsForAnyPlatform = !args.getSrcs().isEmpty();
    Predicate<CxxPlatform> hasObjects;
    if (hasObjectsForAnyPlatform) {
      hasObjects = x -> true;
    } else {
      hasObjects =
          input ->
              !args.getPlatformSrcs().getMatchingValues(input.getFlavor().toString()).isEmpty();
    }

    // Otherwise, we return the generic placeholder of this library, that dependents can use
    // get the real build rules via querying the action graph.
    return new CxxLibraryGroup(
        buildTarget,
        projectFilesystem,
        metadataRuleParams,
        args.getPrivateCxxDeps(),
        args.getExportedCxxDeps(),
        hasObjects.negate(),
        (input, graphBuilderInner) -> {
          ImmutableList<Arg> delegateExportedLinkerFlags =
              delegate
                  .requireDelegate(buildTarget, input, graphBuilderInner)
                  .map(d -> d.getAdditionalExportedLinkerFlags())
                  .orElse(ImmutableList.of());

          ImmutableList<StringWithMacros> flags =
              CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                  args.getExportedLinkerFlags(), args.getExportedPlatformLinkerFlags(), input);
          return RichStream.from(flags)
              .map(
                  CxxDescriptionEnhancer.getStringWithMacrosArgsConverter(
                          buildTarget, cellRoots, graphBuilderInner, input)
                      ::convert)
              .concat(RichStream.from(delegateExportedLinkerFlags))
              .toImmutableList();
        },
        (input, graphBuilderInner) -> {
          ImmutableList<Arg> delegatePostExportedLinkerFlags = ImmutableList.of();
          ImmutableList<StringWithMacros> flags =
              CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                  args.getExportedPostLinkerFlags(),
                  args.getExportedPostPlatformLinkerFlags(),
                  input);
          return RichStream.from(flags)
              .map(
                  CxxDescriptionEnhancer.getStringWithMacrosArgsConverter(
                          buildTarget, cellRoots, graphBuilderInner, input)
                      ::convert)
              .concat(RichStream.from(delegatePostExportedLinkerFlags))
              .toImmutableList();
        },
        (cxxPlatform, ruleResolverInner, pathResolverInner, includePrivateLinkerFlags) ->
            getSharedLibraryNativeLinkTargetInput(
                buildTarget,
                projectFilesystem,
                ruleResolverInner,
                cellRoots,
                cxxBuckConfig,
                cxxPlatform,
                args,
                cxxDeps.get(ruleResolverInner, cxxPlatform),
                includePrivateLinkerFlags
                    ? CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                        args.getLinkerFlags(), args.getPlatformLinkerFlags(), cxxPlatform)
                    : ImmutableList.of(),
                CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                    args.getExportedLinkerFlags(),
                    args.getExportedPlatformLinkerFlags(),
                    cxxPlatform),
                includePrivateLinkerFlags
                    ? CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                        args.getPostLinkerFlags(), args.getPostPlatformLinkerFlags(), cxxPlatform)
                    : ImmutableList.of(),
                CxxFlags.getFlagsWithMacrosWithPlatformMacroExpansion(
                    args.getExportedPostLinkerFlags(),
                    args.getExportedPostPlatformLinkerFlags(),
                    cxxPlatform),
                args.getFrameworks(),
                args.getLibraries(),
                transitiveCxxPreprocessorInputFunction,
                delegate.requireDelegate(buildTarget, cxxPlatform, ruleResolverInner)),
        args.getSupportedPlatformsRegex(),
        args.getFrameworks(),
        args.getLibraries(),
        args.getForceStatic().orElse(false)
            ? NativeLinkableGroup.Linkage.STATIC
            : args.getPreferredLinkage().orElse(NativeLinkableGroup.Linkage.ANY),
        args.getLinkWhole().orElse(false),
        args.getSoname(),
        args.getTests(),
        args.getCanBeAsset().orElse(false),
        !buildTarget
            .getFlavors()
            .contains(CxxDescriptionEnhancer.EXPORTED_HEADER_SYMLINK_TREE_FLAVOR),
        args.isReexportAllHeaderDependencies()
            .orElse(cxxBuckConfig.getDefaultReexportAllHeaderDependencies()),
        args.getSupportsMergedLinking().orElse(true),
        delegate);
  }