public BuildRule createBuildRule()

in src/com/facebook/buck/features/rust/RustLibraryDescription.java [140:508]


  public BuildRule createBuildRule(
      BuildRuleCreationContextWithTargetGraph context,
      BuildTarget buildTarget,
      BuildRuleParams params,
      RustLibraryDescriptionArg args) {
    ActionGraphBuilder graphBuilder = context.getActionGraphBuilder();
    ProjectFilesystem projectFilesystem = context.getProjectFilesystem();
    CxxDeps allDeps =
        CxxDeps.builder()
            .addDeps(args.getDeps())
            .addDeps(args.getNamedDeps().values())
            .addPlatformDeps(args.getPlatformDeps())
            .build();

    Function<RustPlatform, Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>>>
        getRustcArgsEnv =
            rustPlatform -> {
              StringWithMacrosConverter converter =
                  RustCompileUtils.getMacroExpander(
                      context, buildTarget, rustPlatform.getCxxPlatform());

              ImmutableList.Builder<Arg> rustcArgs = ImmutableList.builder();
              RustCompileUtils.addFeatures(buildTarget, args.getFeatures(), rustcArgs);
              RustCompileUtils.addTargetTripleForFlavor(rustPlatform.getFlavor(), rustcArgs);
              rustcArgs.addAll(rustPlatform.getRustLibraryFlags());
              rustcArgs.addAll(args.getRustcFlags().stream().map(converter::convert).iterator());

              ImmutableSortedMap<String, Arg> env =
                  ImmutableSortedMap.copyOf(
                      Maps.transformValues(args.getEnv(), converter::convert));

              return new Pair<>(rustcArgs.build(), env);
            };

    String crate = args.getCrate().orElse(ruleToCrateName(buildTarget.getShortName()));

    RustToolchain rustToolchain = getRustToolchain(buildTarget.getTargetConfiguration());

    // 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, RustDescriptionEnhancer.Type>> type =
        LIBRARY_TYPE.getFlavorAndValue(buildTarget);

    if (type.isPresent()) {
      // Uncommon case - someone explicitly invoked buck to build a specific flavor as the
      // direct target.
      CrateType crateType;

      Linker.LinkableDepType depType;

      if (args.getProcMacro()) {
        crateType = CrateType.PROC_MACRO;
      } else {
        crateType = type.get().getValue().getCrateType();
      }

      if (crateType.isDynamic()) {
        depType = Linker.LinkableDepType.SHARED;
      } else {
        if (crateType.isPic()) {
          depType = Linker.LinkableDepType.STATIC_PIC;
        } else {
          depType = Linker.LinkableDepType.STATIC;
        }
      }

      RustPlatform platform =
          RustCompileUtils.getRustPlatform(rustToolchain, buildTarget, args)
              .resolve(graphBuilder, buildTarget.getTargetConfiguration());

      Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>> argenv =
          getRustcArgsEnv.apply(platform);

      return requireBuild(
          buildTarget,
          projectFilesystem,
          graphBuilder,
          platform,
          rustBuckConfig,
          argenv.getSecond(),
          argenv.getFirst(),
          /* linkerArgs */ ImmutableList.of(),
          /* linkerInputs */ ImmutableList.of(),
          crate,
          crateType,
          args.getEdition(),
          depType,
          args,
          allDeps.get(graphBuilder, platform.getCxxPlatform()),
          args.getNamedDeps());
    }

    // Common case - we're being invoked to satisfy some other rule's dependency.
    return new RustLibrary(buildTarget, projectFilesystem, params) {
      private final PlatformLockedNativeLinkableGroup.Cache linkableCache =
          LegacyNativeLinkableGroup.getNativeLinkableCache(this);
      // RustLinkable
      @Override
      public Arg getLinkerArg(
          boolean direct,
          boolean isCheck,
          RustPlatform rustPlatform,
          LinkableDepType depType,
          Optional<String> alias) {
        BuildRule rule;
        CrateType crateType;

        // Determine a crate type from preferred linkage and deptype.
        // Procedural Macros (aka, compiler plugins) take priority over check builds
        // as we need the compiler plugin to be able to check the code which depends on the
        // plugin.
        if (isProcMacro()) {
          crateType = CrateType.PROC_MACRO;
        } else if (isCheck) {
          crateType = CrateType.CHECK;
        } else {
          switch (args.getPreferredLinkage()) {
            case ANY:
            default:
              switch (depType) {
                case SHARED:
                  crateType = CrateType.DYLIB;
                  break;
                case STATIC_PIC:
                  crateType = CrateType.RLIB_PIC;
                  break;
                case STATIC:
                default:
                  crateType = CrateType.RLIB;
                  break;
              }
              break;

            case SHARED:
              crateType = CrateType.DYLIB;
              break;

            case STATIC:
              if (depType == Linker.LinkableDepType.STATIC) {
                crateType = CrateType.RLIB;
              } else {
                crateType = CrateType.RLIB_PIC;
              }
              break;
          }
        }

        Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>> argenv =
            getRustcArgsEnv.apply(rustPlatform);

        rule =
            requireBuild(
                buildTarget,
                projectFilesystem,
                graphBuilder,
                rustPlatform,
                rustBuckConfig,
                argenv.getSecond(),
                argenv.getFirst(),
                /* linkerArgs */ ImmutableList.of(),
                /* linkerInputs */ ImmutableList.of(),
                crate,
                crateType,
                args.getEdition(),
                depType,
                args,
                allDeps.get(graphBuilder, rustPlatform.getCxxPlatform()),
                args.getNamedDeps());
        SourcePath rlib = rule.getSourcePathToOutput();
        return new RustLibraryArg(crate, rlib, direct, alias);
      }

      @Override
      public boolean isProcMacro() {
        return args.getProcMacro();
      }

      @Override
      public Linkage getPreferredLinkage() {
        return args.getPreferredLinkage();
      }

      @Override
      public ImmutableMap<String, SourcePath> getRustSharedLibraries(RustPlatform rustPlatform) {
        BuildTarget target = getBuildTarget();

        ImmutableMap.Builder<String, SourcePath> libs = ImmutableMap.builder();
        String sharedLibrarySoname =
            CrateType.DYLIB.filenameFor(target, crate, rustPlatform.getCxxPlatform());

        Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>> argenv =
            getRustcArgsEnv.apply(rustPlatform);

        BuildRule sharedLibraryBuildRule =
            requireBuild(
                buildTarget,
                projectFilesystem,
                graphBuilder,
                rustPlatform,
                rustBuckConfig,
                argenv.getSecond(),
                argenv.getFirst(),
                /* linkerArgs */ ImmutableList.of(),
                /* linkerInputs */ ImmutableList.of(),
                crate,
                CrateType.DYLIB,
                args.getEdition(),
                LinkableDepType.SHARED,
                args,
                allDeps.get(graphBuilder, rustPlatform.getCxxPlatform()),
                args.getNamedDeps());
        libs.put(sharedLibrarySoname, sharedLibraryBuildRule.getSourcePathToOutput());
        return libs.build();
      }

      @Override
      public Iterable<BuildRule> getRustLinakbleDeps(RustPlatform rustPlatform) {
        return allDeps.get(graphBuilder, rustPlatform.getCxxPlatform());
      }

      // NativeLinkable
      @Override
      public Iterable<? extends NativeLinkableGroup> getNativeLinkableDeps(
          BuildRuleResolver ruleResolver) {
        return ImmutableList.of();
      }

      @Override
      public Iterable<NativeLinkableGroup> getNativeLinkableExportedDeps(
          BuildRuleResolver ruleResolver) {
        return RichStream.from(allDeps.getForAllPlatforms(ruleResolver))
            .filter(NativeLinkableGroup.class)
            .toImmutableList();
      }

      @Override
      public PlatformLockedNativeLinkableGroup.Cache getNativeLinkableCompatibilityCache() {
        return linkableCache;
      }

      @Override
      public Iterable<? extends NativeLinkableGroup> getNativeLinkableExportedDepsForPlatform(
          CxxPlatform cxxPlatform, ActionGraphBuilder graphBuilder) {
        // We want to skip over all the transitive Rust deps, and only return non-Rust
        // deps at the edge of the graph
        ImmutableList.Builder<NativeLinkableGroup> nativedeps = ImmutableList.builder();

        RustPlatform rustPlatform =
            getRustToolchain(buildTarget.getTargetConfiguration())
                .getRustPlatforms()
                .getValue(cxxPlatform.getFlavor())
                .resolve(graphBuilder, buildTarget.getTargetConfiguration());
        new AbstractBreadthFirstTraversal<BuildRule>(allDeps.get(graphBuilder, cxxPlatform)) {
          @Override
          public Iterable<BuildRule> visit(BuildRule rule) {
            if (rule instanceof RustLinkable) {
              // Rust rule - we just want to visit the children
              return ((RustLinkable) rule).getRustLinakbleDeps(rustPlatform);
            }
            if (rule instanceof NativeLinkableGroup) {
              nativedeps.add((NativeLinkableGroup) rule);
            }
            return ImmutableList.of();
          }
        }.start();

        return nativedeps.build();
      }

      @Override
      public NativeLinkableInput getNativeLinkableInput(
          CxxPlatform cxxPlatform,
          Linker.LinkableDepType depType,
          boolean forceLinkWhole,
          ActionGraphBuilder graphBuilder,
          TargetConfiguration targetConfiguration) {
        CrateType crateType;

        switch (depType) {
          case SHARED:
            crateType = CrateType.CDYLIB;
            break;

          case STATIC_PIC:
            crateType = CrateType.STATIC_PIC;
            break;

          case STATIC:
          default:
            crateType = CrateType.STATIC;
            break;
        }

        RustPlatform rustPlatform =
            getRustToolchain(targetConfiguration)
                .getRustPlatforms()
                .getValue(cxxPlatform.getFlavor())
                .resolve(graphBuilder, buildTarget.getTargetConfiguration());
        Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>> argenv =
            getRustcArgsEnv.apply(rustPlatform);

        BuildRule rule =
            requireBuild(
                buildTarget,
                projectFilesystem,
                graphBuilder,
                rustPlatform,
                rustBuckConfig,
                argenv.getSecond(),
                argenv.getFirst(),
                /* linkerArgs */ ImmutableList.of(),
                /* linkerInputs */ ImmutableList.of(),
                crate,
                crateType,
                args.getEdition(),
                depType,
                args,
                allDeps.get(graphBuilder, rustPlatform.getCxxPlatform()),
                args.getNamedDeps());

        SourcePath lib = rule.getSourcePathToOutput();
        SourcePathArg arg = SourcePathArg.of(lib);

        return NativeLinkableInput.builder().addArgs(arg).build();
      }

      @Override
      public Linkage getPreferredLinkage(CxxPlatform cxxPlatform) {
        return args.getPreferredLinkage();
      }

      @Override
      public ImmutableMap<String, SourcePath> getSharedLibraries(
          CxxPlatform cxxPlatform, ActionGraphBuilder graphBuilder) {
        ImmutableMap.Builder<String, SourcePath> libs = ImmutableMap.builder();
        String sharedLibrarySoname =
            CrateType.DYLIB.filenameFor(getBuildTarget(), crate, cxxPlatform);
        RustPlatform rustPlatform =
            getRustToolchain(buildTarget.getTargetConfiguration())
                .getRustPlatforms()
                .getValue(cxxPlatform.getFlavor())
                .resolve(graphBuilder, buildTarget.getTargetConfiguration());

        Pair<ImmutableList<Arg>, ImmutableSortedMap<String, Arg>> argenv =
            getRustcArgsEnv.apply(rustPlatform);

        BuildRule sharedLibraryBuildRule =
            requireBuild(
                buildTarget,
                projectFilesystem,
                graphBuilder,
                rustPlatform,
                rustBuckConfig,
                argenv.getSecond(),
                argenv.getFirst(),
                /* linkerArgs */ ImmutableList.of(),
                /* linkerInputs */ ImmutableList.of(),
                crate,
                CrateType.CDYLIB,
                args.getEdition(),
                LinkableDepType.SHARED,
                args,
                allDeps.get(graphBuilder, rustPlatform.getCxxPlatform()),
                args.getNamedDeps());
        libs.put(sharedLibrarySoname, sharedLibraryBuildRule.getSourcePathToOutput());
        return libs.build();
      }
    };
  }