private static RustCompileRule createBuild()

in src/com/facebook/buck/features/rust/RustCompileUtils.java [108:318]


  private static RustCompileRule createBuild(
      BuildTarget target,
      String crateName,
      ProjectFilesystem projectFilesystem,
      ActionGraphBuilder graphBuilder,
      RustPlatform rustPlatform,
      RustBuckConfig rustConfig,
      ImmutableSortedMap<String, Arg> environment,
      ImmutableList<Arg> extraFlags,
      ImmutableList<Arg> extraLinkerFlags,
      Iterable<Arg> linkerInputs,
      CrateType crateType,
      Optional<String> edition,
      LinkableDepType depType,
      boolean rpath,
      ImmutableSortedMap<SourcePath, Optional<String>> mappedSources,
      String rootModule,
      boolean forceRlib,
      boolean preferStatic,
      Iterable<BuildRule> ruledeps,
      ImmutableMap<String, BuildTarget> depsAliases,
      Optional<String> incremental) {
    CxxPlatform cxxPlatform = rustPlatform.getCxxPlatform();
    ImmutableList.Builder<Arg> linkerArgs = ImmutableList.builder();

    String filename = crateType.filenameFor(target, crateName, cxxPlatform);

    // Use the C linker configuration for CDYLIB
    if (crateType == CrateType.CDYLIB) {
      Linker linker = cxxPlatform.getLd().resolve(graphBuilder, target.getTargetConfiguration());
      linkerArgs.addAll(StringArg.from(linker.soname(filename)));
    }

    Stream.concat(rustPlatform.getLinkerArgs().stream(), extraLinkerFlags.stream())
        .forEach(linkerArgs::add);

    linkerArgs.addAll(linkerInputs);

    ImmutableList.Builder<Arg> args = ImmutableList.builder();
    ImmutableList.Builder<Arg> depArgs = ImmutableList.builder();

    String relocModel;
    if (crateType.isPic()) {
      relocModel = "pic";
    } else {
      relocModel = "static";
    }

    Stream<StringArg> checkArgs;
    if (crateType.isCheck()) {
      args.add(StringArg.of("--emit=metadata"));
      checkArgs = rustPlatform.getRustCheckFlags().stream();
    } else {
      checkArgs = Stream.of();
    }

    if (crateType.isSaveAnalysis()) {
      // This is an unstable option - not clear what the path to stabilization is.
      args.add(StringArg.of("-Zsave-analysis"));
    }

    Stream.of(
            Stream.of(
                    String.format("--crate-name=%s", crateName),
                    String.format("--crate-type=%s", crateType),
                    String.format("-Crelocation-model=%s", relocModel))
                .map(StringArg::of),
            extraFlags.stream(),
            checkArgs)
        .flatMap(x -> x)
        .forEach(args::add);

    args.add(StringArg.of(String.format("--edition=%s", edition.orElse(rustConfig.getEdition()))));

    if (incremental.isPresent()) {
      Path path =
          projectFilesystem
              .getBuckPaths()
              .getTmpDir()
              .resolve("rust-incremental")
              .resolve(incremental.get());

      for (Flavor f : target.getFlavors().getSet()) {
        path = path.resolve(f.getName());
      }
      args.add(StringArg.of(String.format("-Cincremental=%s", path)));
    }

    LinkableDepType rustDepType;
    // Work out the linkage for our dependencies
    switch (depType) {
      case SHARED:
        // If we're building a CDYLIB then our Rust dependencies need to be static
        // Alternatively, if we're using forceRlib then anything else needs rlib deps.
        if (forceRlib || crateType == CrateType.CDYLIB) {
          rustDepType = LinkableDepType.STATIC_PIC;
        } else {
          rustDepType = LinkableDepType.SHARED;
        }
        break;

      case STATIC:
        // If we're PIC, all our dependencies need to be as well
        if (crateType.isPic()) {
          rustDepType = LinkableDepType.STATIC_PIC;
        } else {
          rustDepType = LinkableDepType.STATIC;
        }
        break;

      case STATIC_PIC:
      default: // Unnecessary?
        rustDepType = depType;
        break;
    }

    // Build reverse mapping from build targets to aliases. This might be a 1:many relationship
    // (ie, the crate may import another crate multiple times under multiple names). If there's
    // nothing here then the default name is used.
    Multimap<BuildTarget, String> revAliasMap =
        Multimaps.invertFrom(
            Multimaps.forMap(depsAliases), MultimapBuilder.hashKeys().arrayListValues().build());

    // Find direct and transitive Rust deps. We do this in two passes, since a dependency that's
    // both direct and transitive needs to be listed on the command line in each form.
    //
    // This could end up with a lot of redundant parameters (lots of rlibs in one directory),
    // but Arg isn't comparable, so we can't put it in a Set.

    // First pass - direct deps
    RichStream.from(ruledeps)
        .filter(RustLinkable.class::isInstance)
        .forEach(
            rule -> {
              addDependencyArgs(
                  rule, rustPlatform, crateType, depArgs, revAliasMap, rustDepType, true);
            });

    // Second pass - indirect deps
    new AbstractBreadthFirstTraversal<BuildRule>(
        RichStream.from(ruledeps)
            .filter(RustLinkable.class)
            .flatMap(r -> RichStream.from(r.getRustLinakbleDeps(rustPlatform)))
            .collect(ImmutableList.toImmutableList())) {
      @Override
      public Iterable<BuildRule> visit(BuildRule rule) {
        Iterable<BuildRule> deps = ImmutableSortedSet.of();
        if (rule instanceof RustLinkable) {
          deps = ((RustLinkable) rule).getRustLinakbleDeps(rustPlatform);

          addDependencyArgs(
              rule, rustPlatform, crateType, depArgs, revAliasMap, rustDepType, false);
        }
        return deps;
      }
    }.start();

    // A native crate output is no longer intended for consumption by the Rust toolchain;
    // it's either an executable, or a native library that C/C++ can link with. Rust DYLIBs
    // also need all dependencies available.
    if (crateType.needAllDeps()) {
      // Get the topologically sorted native linkables.
      ImmutableMap<BuildTarget, NativeLinkableGroup> roots =
          NativeLinkableGroups.getNativeLinkableRoots(
              ruledeps,
              (Function<? super BuildRule, Optional<Iterable<? extends BuildRule>>>)
                  r ->
                      r instanceof RustLinkable
                          ? Optional.of(((RustLinkable) r).getRustLinakbleDeps(rustPlatform))
                          : Optional.empty());

      ImmutableList<Arg> nativeArgs =
          NativeLinkables.getTransitiveNativeLinkableInput(
                  graphBuilder,
                  target.getTargetConfiguration(),
                  Iterables.transform(
                      roots.values(), g -> g.getNativeLinkable(cxxPlatform, graphBuilder)),
                  depType)
              .getArgs();

      // Add necessary rpaths if we're dynamically linking with things
      if (rpath && depType == Linker.LinkableDepType.SHARED) {
        args.add(StringArg.of("-Crpath"));
      }

      linkerArgs.addAll(nativeArgs);
    }

    // If we want shared deps or are building a dynamic rlib, make sure we prefer
    // dynamic dependencies (esp to get dynamic dependency on standard libs)
    if ((!preferStatic && depType == Linker.LinkableDepType.SHARED)
        || crateType == CrateType.DYLIB) {
      args.add(StringArg.of("-Cprefer-dynamic"));
    }

    return RustCompileRule.from(
        graphBuilder,
        target,
        projectFilesystem,
        filename,
        rustPlatform.getRustCompiler().resolve(graphBuilder, target.getTargetConfiguration()),
        rustPlatform.getLinkerProvider().resolve(graphBuilder, target.getTargetConfiguration()),
        args.build(),
        depArgs.build(),
        linkerArgs.build(),
        environment,
        mappedSources,
        rootModule,
        rustConfig.getRemapSrcPaths(),
        rustPlatform.getXcrunSdkPath().map(path -> path.toString()));
  }