@Test
  public void testCreateBuildRule() throws Exception {
    // Set up a #halide-compiler rule, then set up a halide_library rule, and
    // check that the library rule depends on the compiler rule.
    BuildTarget compilerTarget =
        BuildTargetFactory.newInstance("//:rule")
            .withFlavors(HalideLibraryDescription.HALIDE_COMPILER_FLAVOR);
    BuildTarget libTarget = BuildTargetFactory.newInstance("//:rule");

    ProjectFilesystem filesystem = new FakeProjectFilesystem();
    HalideLibraryBuilder compilerBuilder = new HalideLibraryBuilder(compilerTarget);
    compilerBuilder.setSrcs(
        ImmutableSortedSet.of(SourceWithFlags.of(new FakeSourcePath("main.cpp"))));
    HalideLibraryBuilder libBuilder = new HalideLibraryBuilder(libTarget);
    TargetGraph targetGraph =
        TargetGraphFactory.newInstance(compilerBuilder.build(), libBuilder.build());
    BuildRuleResolver resolver =
        new BuildRuleResolver(targetGraph, new BuildTargetNodeToBuildRuleTransformer());
    CxxBinary compiler = (CxxBinary) compilerBuilder.build(resolver, filesystem, targetGraph);
    HalideLibrary lib = (HalideLibrary) libBuilder.build(resolver, filesystem, targetGraph);
    // Check that we picked up the implicit dependency on the #halide-compiler
    // version of the rule.
    assertEquals(lib.getDeps(), ImmutableSortedSet.<BuildRule>of(compiler));

    // Check that the library rule has the correct preprocessor input.
    CxxPlatform cxxPlatform = CxxLibraryBuilder.createDefaultPlatform();
    String headerName = "rule.h";
    Path headerPath = BuildTargets.getGenPath(libTarget, "%s/" + headerName);
    Path headerRoot =
        CxxDescriptionEnhancer.getHeaderSymlinkTreePath(
            libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC);
    assertEquals(
        CxxPreprocessorInput.builder()
            .addRules(
                CxxDescriptionEnhancer.createHeaderSymlinkTreeTarget(
                    libTarget, cxxPlatform.getFlavor(), HeaderVisibility.PUBLIC))
            .setIncludes(
                CxxHeaders.builder()
                    .putNameToPathMap(
                        Paths.get(headerName), new BuildTargetSourcePath(libTarget, headerPath))
                    .putFullNameToPathMap(
                        headerRoot.resolve(headerName),
                        new BuildTargetSourcePath(libTarget, headerPath))
                    .build())
            .addSystemIncludeRoots(headerRoot)
            .build(),
        lib.getCxxPreprocessorInput(cxxPlatform, HeaderVisibility.PUBLIC));

    // Check that the library rule has the correct native linkable input.
    NativeLinkableInput input =
        lib.getNativeLinkableInput(cxxPlatform, Linker.LinkableDepType.STATIC);
    BuildRule buildRule =
        FluentIterable.from(input.getArgs())
            .transformAndConcat(Arg.getDepsFunction(new SourcePathResolver(resolver)))
            .get(0);
    assertTrue(buildRule instanceof HalideLibrary);
  }
 public CxxLibraryEnhancement(
     BuildRuleParams params,
     Optional<Boolean> useCxxLibraries,
     BuildRuleResolver resolver,
     SourcePathResolver pathResolver,
     CxxPlatform cxxPlatform)
     throws NoSuchBuildTargetException {
   if (useCxxLibraries.or(false)) {
     SymlinkTree nativeLibsSymlinkTree =
         buildNativeLibsSymlinkTreeRule(params, pathResolver, cxxPlatform);
     updatedParams =
         params.appendExtraDeps(
             ImmutableList.<BuildRule>builder()
                 .add(nativeLibsSymlinkTree)
                 // Add all the native libraries as first-order dependencies.
                 // This has two effects:
                 // (1) They become runtime deps because JavaTest adds all first-order deps.
                 // (2) They affect the JavaTest's RuleKey, so changing them will invalidate
                 // the test results cache.
                 .addAll(
                     pathResolver.filterBuildRuleInputs(
                         nativeLibsSymlinkTree.getLinks().values()))
                 .build());
     nativeLibsEnvironment =
         ImmutableMap.of(
             cxxPlatform.getLd().resolve(resolver).searchPathEnvVar(),
             nativeLibsSymlinkTree.getRoot().toString());
   } else {
     updatedParams = params;
     nativeLibsEnvironment = ImmutableMap.of();
   }
 }
  private AppleCxxPlatform getAppleCxxPlatformForBuildTarget(BuildTarget target) {
    Optional<FatBinaryInfo> fatBinaryInfo =
        FatBinaryInfo.create(platformFlavorsToAppleCxxPlatforms, target);
    AppleCxxPlatform appleCxxPlatform;
    if (fatBinaryInfo.isPresent()) {
      appleCxxPlatform = fatBinaryInfo.get().getRepresentativePlatform();
    } else {
      CxxPlatform cxxPlatform = getCxxPlatformForBuildTarget(target);
      appleCxxPlatform = platformFlavorsToAppleCxxPlatforms.get(cxxPlatform.getFlavor());
      if (appleCxxPlatform == null) {
        throw new HumanReadableException(
            "%s: Apple bundle requires an Apple platform, found '%s'",
            target, cxxPlatform.getFlavor().getName());
      }
    }

    return appleCxxPlatform;
  }
示例#4
0
 @Override
 public ImmutableMap<BuildTarget, CxxPreprocessorInput> getTransitiveCxxPreprocessorInput(
     TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) {
   Pair<Flavor, HeaderVisibility> key = new Pair<>(cxxPlatform.getFlavor(), headerVisibility);
   ImmutableMap<BuildTarget, CxxPreprocessorInput> result = cxxPreprocessorInputCache.get(key);
   if (result == null) {
     ImmutableMap.Builder<BuildTarget, CxxPreprocessorInput> builder = ImmutableMap.builder();
     builder.put(
         getBuildTarget(), getCxxPreprocessorInput(targetGraph, cxxPlatform, headerVisibility));
     result = builder.build();
     cxxPreprocessorInputCache.put(key, result);
   }
   return result;
 }
 private <A extends Arg> BuildRule createExtensionBuildRule(
     BuildRuleParams params,
     BuildRuleResolver ruleResolver,
     PythonPlatform pythonPlatform,
     CxxPlatform cxxPlatform,
     A args)
     throws NoSuchBuildTargetException {
   SourcePathResolver pathResolver = new SourcePathResolver(ruleResolver);
   String extensionName = getExtensionName(params.getBuildTarget());
   Path extensionPath =
       getExtensionPath(
           params.getProjectFilesystem(),
           params.getBuildTarget(),
           pythonPlatform.getFlavor(),
           cxxPlatform.getFlavor());
   return CxxLinkableEnhancer.createCxxLinkableBuildRule(
       cxxBuckConfig,
       cxxPlatform,
       params,
       ruleResolver,
       pathResolver,
       getExtensionTarget(
           params.getBuildTarget(), pythonPlatform.getFlavor(), cxxPlatform.getFlavor()),
       Linker.LinkType.SHARED,
       Optional.of(extensionName),
       extensionPath,
       Linker.LinkableDepType.SHARED,
       FluentIterable.from(params.getDeps()).filter(NativeLinkable.class),
       args.cxxRuntimeType,
       Optional.<SourcePath>absent(),
       ImmutableSet.<BuildTarget>of(),
       NativeLinkableInput.builder()
           .setArgs(getExtensionArgs(params, ruleResolver, pathResolver, cxxPlatform, args))
           .setFrameworks(args.frameworks.or(ImmutableSortedSet.<FrameworkPath>of()))
           .setLibraries(args.libraries.or(ImmutableSortedSet.<FrameworkPath>of()))
           .build());
 }
  private <A extends Arg> BuildRule getFlavoredBinaryRule(
      TargetGraph targetGraph,
      final BuildRuleParams params,
      final BuildRuleResolver resolver,
      A args) {
    // Cxx targets must have one Platform Flavor set otherwise nothing gets compiled.
    ImmutableSet<Flavor> flavors =
        params
            .getBuildTarget()
            .withoutFlavors(ImmutableSet.of(ReactNativeFlavors.DO_NOT_BUNDLE))
            .getFlavors();
    if (!cxxPlatformFlavorDomain.containsAnyOf(flavors)) {
      flavors =
          new ImmutableSet.Builder<Flavor>()
              .addAll(flavors)
              .add(defaultCxxPlatform.getFlavor())
              .build();
    }

    final TargetNode<?> binaryTargetNode = Preconditions.checkNotNull(targetGraph.get(args.binary));
    // If the binary target of the AppleBundle is an AppleLibrary then the build flavor
    // must be specified.
    if (binaryTargetNode.getDescription() instanceof AppleLibraryDescription
        && (Sets.intersection(
                    SUPPORTED_LIBRARY_FLAVORS, binaryTargetNode.getBuildTarget().getFlavors())
                .size()
            != 1)) {
      throw new HumanReadableException(
          "AppleExtension bundle [%s] must have exactly one of these flavors: [%s].",
          binaryTargetNode.getBuildTarget().toString(),
          Joiner.on(", ").join(SUPPORTED_LIBRARY_FLAVORS));
    }

    BuildRuleParams binaryRuleParams =
        new BuildRuleParams(
            args.binary,
            Suppliers.ofInstance(
                BuildRules.toBuildRulesFor(
                    params.getBuildTarget(), resolver, binaryTargetNode.getDeclaredDeps())),
            Suppliers.ofInstance(
                BuildRules.toBuildRulesFor(
                    params.getBuildTarget(), resolver, binaryTargetNode.getExtraDeps())),
            params.getProjectFilesystem(),
            params.getCellRoots(),
            params.getRuleKeyBuilderFactory());

    return CxxDescriptionEnhancer.requireBuildRule(
        targetGraph, binaryRuleParams, resolver, flavors.toArray(new Flavor[0]));
  }
示例#7
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());
  }
示例#8
0
  @Override
  public CxxPreprocessorInput getCxxPreprocessorInput(
      TargetGraph targetGraph, CxxPlatform cxxPlatform, HeaderVisibility headerVisibility) {
    switch (headerVisibility) {
      case PUBLIC:
        return CxxPreprocessorInput.builder()
            .from(
                CxxPreprocessables.getCxxPreprocessorInput(
                    targetGraph,
                    params,
                    ruleResolver,
                    cxxPlatform.getFlavor(),
                    headerVisibility,
                    CxxPreprocessables.IncludeType.SYSTEM,
                    ImmutableMultimap.<CxxSource.Type, String>of(), /* exportedPreprocessorFlags */
                    cxxPlatform,
                    ImmutableList.<FrameworkPath>of())) /* frameworks */
            .build();
      case PRIVATE:
        return CxxPreprocessorInput.EMPTY;
    }

    throw new RuntimeException("Invalid header visibility: " + headerVisibility);
  }
  /** Propagate the bundle's platform flavors to its dependents. */
  @Override
  public ImmutableSet<BuildTarget> findDepsForTargetFromConstructorArgs(
      BuildTarget buildTarget,
      Function<Optional<String>, Path> cellRoots,
      AppleBundleDescription.Arg constructorArg) {
    if (!constructorArg.deps.isPresent()) {
      return ImmutableSet.of();
    }

    if (!cxxPlatformFlavorDomain.containsAnyOf(buildTarget.getFlavors())) {
      buildTarget =
          BuildTarget.builder(buildTarget)
              .addAllFlavors(ImmutableSet.of(defaultCxxPlatform.getFlavor()))
              .build();
    }

    Optional<FatBinaryInfo> fatBinaryInfo =
        FatBinaryInfo.create(platformFlavorsToAppleCxxPlatforms, buildTarget);
    CxxPlatform cxxPlatform;
    if (fatBinaryInfo.isPresent()) {
      AppleCxxPlatform appleCxxPlatform = fatBinaryInfo.get().getRepresentativePlatform();
      cxxPlatform = appleCxxPlatform.getCxxPlatform();
    } else {
      cxxPlatform = getCxxPlatformForBuildTarget(buildTarget);
    }

    String platformName = cxxPlatform.getFlavor().getName();
    final Flavor actualWatchFlavor;
    if (ApplePlatform.isSimulator(platformName)) {
      actualWatchFlavor = ImmutableFlavor.builder().name("watchsimulator-i386").build();
    } else if (platformName.startsWith(ApplePlatform.Name.IPHONEOS)
        || platformName.startsWith(ApplePlatform.Name.WATCHOS)) {
      actualWatchFlavor = ImmutableFlavor.builder().name("watchos-armv7k").build();
    } else {
      actualWatchFlavor = ImmutableFlavor.builder().name(platformName).build();
    }

    FluentIterable<BuildTarget> depsExcludingBinary =
        FluentIterable.from(constructorArg.deps.get())
            .filter(Predicates.not(Predicates.equalTo(constructorArg.binary)));

    FluentIterable<BuildTarget> targetsWithPlatformFlavors =
        depsExcludingBinary.filter(BuildTargets.containsFlavors(cxxPlatformFlavorDomain));

    FluentIterable<BuildTarget> targetsWithoutPlatformFlavors =
        depsExcludingBinary.filter(
            Predicates.not(BuildTargets.containsFlavors(cxxPlatformFlavorDomain)));

    FluentIterable<BuildTarget> watchTargets =
        targetsWithoutPlatformFlavors
            .filter(BuildTargets.containsFlavor(WATCH))
            .transform(
                new Function<BuildTarget, BuildTarget>() {
                  @Override
                  public BuildTarget apply(BuildTarget input) {
                    return BuildTarget.builder(input.withoutFlavors(ImmutableSet.of(WATCH)))
                        .addFlavors(actualWatchFlavor)
                        .build();
                  }
                });

    targetsWithoutPlatformFlavors =
        targetsWithoutPlatformFlavors.filter(Predicates.not(BuildTargets.containsFlavor(WATCH)));

    return ImmutableSet.<BuildTarget>builder()
        .addAll(targetsWithPlatformFlavors)
        .addAll(watchTargets)
        .addAll(
            BuildTargets.propagateFlavorDomains(
                buildTarget,
                ImmutableSet.<FlavorDomain<?>>of(cxxPlatformFlavorDomain),
                targetsWithoutPlatformFlavors))
        .build();
  }
  private ImmutableList<com.facebook.buck.rules.args.Arg> getExtensionArgs(
      BuildRuleParams params,
      BuildRuleResolver ruleResolver,
      SourcePathResolver pathResolver,
      CxxPlatform cxxPlatform,
      Arg args)
      throws NoSuchBuildTargetException {

    // Extract all C/C++ sources from the constructor arg.
    ImmutableMap<String, CxxSource> srcs =
        CxxDescriptionEnhancer.parseCxxSources(
            params.getBuildTarget(), pathResolver, cxxPlatform, args);
    ImmutableMap<Path, SourcePath> headers =
        CxxDescriptionEnhancer.parseHeaders(
            params.getBuildTarget(), pathResolver, Optional.of(cxxPlatform), args);

    // 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,
            headers,
            HeaderVisibility.PRIVATE);
    ImmutableList<CxxPreprocessorInput> cxxPreprocessorInput =
        CxxDescriptionEnhancer.collectCxxPreprocessorInput(
            params,
            cxxPlatform,
            CxxFlags.getLanguageFlags(
                args.preprocessorFlags,
                args.platformPreprocessorFlags,
                args.langPreprocessorFlags,
                cxxPlatform),
            ImmutableList.of(headerSymlinkTree),
            ImmutableSet.<FrameworkPath>of(),
            CxxPreprocessables.getTransitiveCxxPreprocessorInput(cxxPlatform, params.getDeps()));

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

    ImmutableList.Builder<com.facebook.buck.rules.args.Arg> argsBuilder = ImmutableList.builder();
    argsBuilder.addAll(
        StringArg.from(CxxFlags.getFlags(args.linkerFlags, args.platformLinkerFlags, cxxPlatform)));

    // 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/", cxxPlatform.getLd().resolve(ruleResolver).libOrigin()))));

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

    return argsBuilder.build();
  }
示例#11
0
  @VisibleForTesting
  static Builder createBuilder(
      BuckConfig config,
      ProcessExecutor processExecutor,
      AndroidDirectoryResolver androidDirectoryResolver,
      Optional<Path> testTempDirOverride)
      throws InterruptedException, IOException {

    Platform platform = Platform.detect();

    AndroidBuckConfig androidConfig = new AndroidBuckConfig(config, platform);
    Optional<String> ndkVersion = androidConfig.getNdkVersion();
    // If a NDK version isn't specified, we've got to reach into the runtime environment to find
    // out which one we will end up using.
    if (!ndkVersion.isPresent()) {
      ndkVersion = androidDirectoryResolver.getNdkVersion();
    }

    AppleConfig appleConfig = new AppleConfig(config);
    final AppleBundle.DebugInfoFormat defaultDebugInfoFormat = appleConfig.getDebugInfoFormat();

    ImmutableMap.Builder<Flavor, AppleCxxPlatform> platformFlavorsToAppleCxxPlatformsBuilder =
        ImmutableMap.builder();
    buildAppleCxxPlatforms(
        appleConfig.getAppleDeveloperDirectorySupplier(processExecutor),
        appleConfig.getExtraToolchainPaths(),
        appleConfig.getExtraPlatformPaths(),
        config,
        appleConfig,
        platformFlavorsToAppleCxxPlatformsBuilder);
    ImmutableMap<Flavor, AppleCxxPlatform> platformFlavorsToAppleCxxPlatforms =
        platformFlavorsToAppleCxxPlatformsBuilder.build();

    // Setup the NDK C/C++ platforms.
    Optional<Path> ndkRoot = androidDirectoryResolver.findAndroidNdkDir();
    ImmutableMap.Builder<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> ndkCxxPlatformsBuilder =
        ImmutableMap.builder();
    if (ndkRoot.isPresent()) {
      NdkCxxPlatforms.Compiler.Type compilerType =
          androidConfig.getNdkCompiler().or(NdkCxxPlatforms.DEFAULT_COMPILER_TYPE);
      String gccVersion = androidConfig.getNdkGccVersion().or(NdkCxxPlatforms.DEFAULT_GCC_VERSION);
      NdkCxxPlatforms.Compiler compiler =
          ImmutableNdkCxxPlatforms.Compiler.builder()
              .setType(compilerType)
              .setVersion(
                  compilerType == NdkCxxPlatforms.Compiler.Type.GCC
                      ? gccVersion
                      : androidConfig
                          .getNdkClangVersion()
                          .or(NdkCxxPlatforms.DEFAULT_CLANG_VERSION))
              .setGccVersion(gccVersion)
              .build();
      ndkCxxPlatformsBuilder.putAll(
          NdkCxxPlatforms.getPlatforms(
              new ProjectFilesystem(ndkRoot.get()),
              compiler,
              androidConfig.getNdkCxxRuntime().or(NdkCxxPlatforms.DEFAULT_CXX_RUNTIME),
              androidConfig.getNdkAppPlatform().or(NdkCxxPlatforms.DEFAULT_TARGET_APP_PLATFORM),
              androidConfig.getNdkCpuAbis().or(NdkCxxPlatforms.DEFAULT_CPU_ABIS),
              platform));
    }
    ImmutableMap<NdkCxxPlatforms.TargetCpuType, NdkCxxPlatform> ndkCxxPlatforms =
        ndkCxxPlatformsBuilder.build();

    // Construct the C/C++ config wrapping the buck config.
    CxxBuckConfig cxxBuckConfig = new CxxBuckConfig(config);
    ImmutableMap.Builder<Flavor, CxxPlatform> cxxPlatformsBuilder = ImmutableMap.builder();

    // If an Android NDK is present, add platforms for that.  This is mostly useful for
    // testing our Android NDK support for right now.
    for (NdkCxxPlatform ndkCxxPlatform : ndkCxxPlatforms.values()) {
      cxxPlatformsBuilder.put(
          ndkCxxPlatform.getCxxPlatform().getFlavor(), ndkCxxPlatform.getCxxPlatform());
    }

    for (Map.Entry<Flavor, AppleCxxPlatform> entry :
        platformFlavorsToAppleCxxPlatforms.entrySet()) {
      cxxPlatformsBuilder.put(entry.getKey(), entry.getValue().getCxxPlatform());
    }

    // Add the default, config-defined C/C++ platform.
    CxxPlatform systemDefaultCxxPlatform = DefaultCxxPlatforms.build(platform, cxxBuckConfig);
    cxxPlatformsBuilder.put(systemDefaultCxxPlatform.getFlavor(), systemDefaultCxxPlatform);
    ImmutableMap<Flavor, CxxPlatform> cxxPlatformsMap = cxxPlatformsBuilder.build();

    // Get the default platform from config.
    CxxPlatform defaultCxxPlatform =
        CxxPlatforms.getConfigDefaultCxxPlatform(
            cxxBuckConfig, cxxPlatformsMap, systemDefaultCxxPlatform);

    // Add platforms for each cxx flavor obtained from the buck config files
    // from sections of the form cxx#{flavor name}
    ImmutableSet<Flavor> cxxFlavors = CxxBuckConfig.getCxxFlavors(config);
    for (Flavor flavor : cxxFlavors) {
      CxxBuckConfig flavoredCxxBuckConfig = new CxxBuckConfig(config, flavor);
      CxxPlatform defaultPlatformForFlavor =
          CxxPlatforms.getConfigDefaultCxxPlatform(
              flavoredCxxBuckConfig, cxxPlatformsMap, systemDefaultCxxPlatform);
      cxxPlatformsBuilder.put(
          flavor,
          CxxPlatforms.copyPlatformWithFlavorAndConfig(
              defaultPlatformForFlavor, flavoredCxxBuckConfig, flavor));
    }

    cxxPlatformsMap = cxxPlatformsBuilder.build();

    // Build up the final list of C/C++ platforms.
    FlavorDomain<CxxPlatform> cxxPlatforms = new FlavorDomain<>("C/C++ platform", cxxPlatformsMap);

    DBuckConfig dBuckConfig = new DBuckConfig(config);

    ReactNativeBuckConfig reactNativeBuckConfig = new ReactNativeBuckConfig(config);

    RustBuckConfig rustBuckConfig = new RustBuckConfig(config);

    GoBuckConfig goBuckConfig = new GoBuckConfig(config, processExecutor);

    HalideBuckConfig halideBuckConfig = new HalideBuckConfig(config);

    ProGuardConfig proGuardConfig = new ProGuardConfig(config);

    PythonBuckConfig pyConfig = new PythonBuckConfig(config, new ExecutableFinder());
    ImmutableList<PythonPlatform> pythonPlatformsList =
        pyConfig.getPythonPlatforms(processExecutor);
    ImmutableMap.Builder<Flavor, PythonPlatform> pythonPlatformsMapBuilder = ImmutableMap.builder();
    for (PythonPlatform pythonPlatform : pythonPlatformsList) {
      pythonPlatformsMapBuilder.put(pythonPlatform.getFlavor(), pythonPlatform);
    }
    ImmutableMap<Flavor, PythonPlatform> pythonPlatformsMap = pythonPlatformsMapBuilder.build();
    FlavorDomain<PythonPlatform> pythonPlatforms =
        new FlavorDomain<>("Python Platform", pythonPlatformsMap);
    PythonBinaryDescription pythonBinaryDescription =
        new PythonBinaryDescription(pyConfig, pythonPlatforms, defaultCxxPlatform, cxxPlatforms);

    // Look up the timeout to apply to entire test rules.
    Optional<Long> defaultTestRuleTimeoutMs = config.getLong("test", "rule_timeout");

    // Prepare the downloader if we're allowing mid-build downloads
    Downloader downloader;
    DownloadConfig downloadConfig = new DownloadConfig(config);
    if (downloadConfig.isDownloadAtRuntimeOk()) {
      downloader =
          StackedDownloader.createFromConfig(
              config, androidDirectoryResolver.findAndroidSdkDirSafe());
    } else {
      // Or just set one that blows up
      downloader = new ExplodingDownloader();
    }

    Builder builder = builder();

    JavaBuckConfig javaConfig = new JavaBuckConfig(config);
    JavacOptions defaultJavacOptions = javaConfig.getDefaultJavacOptions();

    InferBuckConfig inferBuckConfig = new InferBuckConfig(config);

    CxxBinaryDescription cxxBinaryDescription =
        new CxxBinaryDescription(
            inferBuckConfig, defaultCxxPlatform, cxxPlatforms, cxxBuckConfig.getPreprocessMode());

    CxxLibraryDescription cxxLibraryDescription =
        new CxxLibraryDescription(
            cxxBuckConfig, inferBuckConfig, cxxPlatforms, cxxBuckConfig.getPreprocessMode());

    CodeSignIdentityStore codeSignIdentityStore = CodeSignIdentityStore.fromSystem(processExecutor);
    ProvisioningProfileStore provisioningProfileStore =
        ProvisioningProfileStore.fromSearchPath(appleConfig.getProvisioningProfileSearchPath());

    AppleLibraryDescription appleLibraryDescription =
        new AppleLibraryDescription(
            cxxLibraryDescription,
            cxxPlatforms,
            platformFlavorsToAppleCxxPlatforms,
            defaultCxxPlatform,
            codeSignIdentityStore,
            provisioningProfileStore,
            defaultDebugInfoFormat);
    builder.register(appleLibraryDescription);

    AppleBinaryDescription appleBinaryDescription =
        new AppleBinaryDescription(
            cxxBinaryDescription,
            cxxPlatforms,
            platformFlavorsToAppleCxxPlatforms,
            defaultCxxPlatform,
            codeSignIdentityStore,
            provisioningProfileStore,
            defaultDebugInfoFormat);
    builder.register(appleBinaryDescription);

    // Create an executor service exclusively for the smart dexing step.
    ListeningExecutorService dxExecutorService =
        MoreExecutors.listeningDecorator(
            Executors.newFixedThreadPool(
                SmartDexingStep.determineOptimalThreadCount(),
                new CommandThreadFactory("SmartDexing")));

    builder.register(new AndroidAarDescription(new AndroidManifestDescription(), ndkCxxPlatforms));
    builder.register(
        new AndroidBinaryDescription(
            defaultJavacOptions, proGuardConfig, ndkCxxPlatforms, dxExecutorService));
    builder.register(new AndroidBuildConfigDescription(defaultJavacOptions));
    builder.register(
        new AndroidInstrumentationApkDescription(
            proGuardConfig, defaultJavacOptions, ndkCxxPlatforms, dxExecutorService));
    builder.register(new AndroidInstrumentationTestDescription(defaultTestRuleTimeoutMs));
    builder.register(new AndroidLibraryDescription(defaultJavacOptions));
    builder.register(new AndroidManifestDescription());
    builder.register(new AndroidPrebuiltAarDescription(defaultJavacOptions));
    builder.register(new AndroidReactNativeLibraryDescription(reactNativeBuckConfig));
    builder.register(new AndroidResourceDescription());
    builder.register(new ApkGenruleDescription());
    builder.register(new AppleAssetCatalogDescription());
    builder.register(new ApplePackageDescription());
    AppleBundleDescription appleBundleDescription =
        new AppleBundleDescription(
            appleBinaryDescription,
            appleLibraryDescription,
            cxxPlatforms,
            platformFlavorsToAppleCxxPlatforms,
            defaultCxxPlatform,
            codeSignIdentityStore,
            provisioningProfileStore,
            defaultDebugInfoFormat);
    builder.register(appleBundleDescription);
    builder.register(new AppleResourceDescription());
    builder.register(
        new AppleTestDescription(
            appleConfig,
            appleBundleDescription,
            appleLibraryDescription,
            cxxPlatforms,
            platformFlavorsToAppleCxxPlatforms,
            defaultCxxPlatform,
            codeSignIdentityStore,
            provisioningProfileStore,
            appleConfig.getAppleDeveloperDirectorySupplier(processExecutor)));
    builder.register(new CoreDataModelDescription());
    builder.register(new CSharpLibraryDescription());
    builder.register(cxxBinaryDescription);
    builder.register(cxxLibraryDescription);
    builder.register(
        new CxxPythonExtensionDescription(pythonPlatforms, cxxBuckConfig, cxxPlatforms));
    builder.register(
        new CxxTestDescription(
            cxxBuckConfig, defaultCxxPlatform, cxxPlatforms, defaultTestRuleTimeoutMs));
    builder.register(new DBinaryDescription(dBuckConfig, defaultCxxPlatform));
    builder.register(new DLibraryDescription(dBuckConfig));
    builder.register(
        new DTestDescription(dBuckConfig, defaultTestRuleTimeoutMs, defaultCxxPlatform));
    builder.register(new ExportFileDescription());
    builder.register(new GenruleDescription());
    builder.register(new GenAidlDescription());
    builder.register(new GoBinaryDescription(goBuckConfig, defaultCxxPlatform));
    builder.register(new GoLibraryDescription(goBuckConfig));
    builder.register(
        new GoTestDescription(goBuckConfig, defaultTestRuleTimeoutMs, defaultCxxPlatform));
    builder.register(new GwtBinaryDescription());
    builder.register(
        new HalideLibraryDescription(
            cxxPlatforms, cxxBuckConfig.getPreprocessMode(), halideBuckConfig));
    builder.register(new IosReactNativeLibraryDescription(reactNativeBuckConfig));
    builder.register(new JavaBinaryDescription(defaultJavacOptions, defaultCxxPlatform));
    builder.register(new JavaLibraryDescription(defaultJavacOptions));
    builder.register(
        new JavaTestDescription(
            defaultJavacOptions,
            defaultTestRuleTimeoutMs,
            defaultCxxPlatform,
            testTempDirOverride));
    builder.register(new KeystoreDescription());
    builder.register(new NdkLibraryDescription(ndkVersion, ndkCxxPlatforms));
    OCamlBuckConfig ocamlBuckConfig = new OCamlBuckConfig(platform, config);
    builder.register(new OCamlBinaryDescription(ocamlBuckConfig));
    builder.register(new OCamlLibraryDescription(ocamlBuckConfig));
    builder.register(new PrebuiltCxxLibraryDescription(cxxPlatforms));
    builder.register(new PrebuiltDotNetLibraryDescription());
    builder.register(new PrebuiltJarDescription());
    builder.register(new PrebuiltNativeLibraryDescription());
    builder.register(new PrebuiltOCamlLibraryDescription());
    builder.register(new PrebuiltPythonLibraryDescription());
    builder.register(new ProjectConfigDescription());
    builder.register(pythonBinaryDescription);
    builder.register(new PythonLibraryDescription());
    builder.register(
        new PythonTestDescription(
            pythonBinaryDescription,
            pyConfig,
            pythonPlatforms,
            defaultCxxPlatform,
            defaultTestRuleTimeoutMs,
            cxxPlatforms));
    builder.register(new RemoteFileDescription(downloader));
    builder.register(
        new RobolectricTestDescription(
            defaultJavacOptions,
            defaultTestRuleTimeoutMs,
            defaultCxxPlatform,
            testTempDirOverride));
    builder.register(new RustBinaryDescription(rustBuckConfig));
    builder.register(new RustLibraryDescription(rustBuckConfig));
    builder.register(new ShBinaryDescription());
    builder.register(new ShTestDescription());
    ThriftBuckConfig thriftBuckConfig = new ThriftBuckConfig(config);
    builder.register(
        new ThriftLibraryDescription(
            thriftBuckConfig,
            ImmutableList.of(
                new ThriftJavaEnhancer(thriftBuckConfig, defaultJavacOptions),
                new ThriftCxxEnhancer(thriftBuckConfig, cxxLibraryDescription, /* cpp2 */ false),
                new ThriftCxxEnhancer(thriftBuckConfig, cxxLibraryDescription, /* cpp2 */ true),
                new ThriftPythonEnhancer(thriftBuckConfig, ThriftPythonEnhancer.Type.NORMAL),
                new ThriftPythonEnhancer(thriftBuckConfig, ThriftPythonEnhancer.Type.TWISTED))));
    builder.register(new XcodePostbuildScriptDescription());
    builder.register(new XcodePrebuildScriptDescription());
    builder.register(new XcodeWorkspaceConfigDescription());
    builder.register(new ZipDescription());

    builder.setCxxPlatforms(cxxPlatforms);
    builder.setDefaultCxxPlatform(defaultCxxPlatform);

    return builder;
  }