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()));
}