in src/com/facebook/buck/features/go/CGoLibrary.java [95:320]
public static BuildRule create(
BuildRuleParams params,
BuildTarget buildTarget,
ProjectFilesystem projectFilesystem,
ActionGraphBuilder graphBuilder,
CellPathResolver cellRoots,
CxxBuckConfig cxxBuckConfig,
GoPlatform platform,
CgoLibraryDescriptionArg args,
Iterable<BuildTarget> cxxDeps,
Tool cgo) {
CxxDeps allDeps =
CxxDeps.builder().addDeps(cxxDeps).addPlatformDeps(args.getPlatformDeps()).build();
// build cxxPreprocessorInputs and collect include flags (used by cgo
// compiler)
ImmutableList<BuildRule> cxxDepsRules =
Streams.stream(cxxDeps)
.map(graphBuilder::requireRule)
.collect(ImmutableList.toImmutableList());
Collection<CxxPreprocessorInput> cxxPreprocessorInputs =
CxxPreprocessables.getTransitiveCxxPreprocessorInputFromDeps(
platform.getCxxPlatform(), graphBuilder, cxxDepsRules);
PreprocessorFlags.Builder ppFlagsBuilder = PreprocessorFlags.builder();
for (CxxPreprocessorInput input : cxxPreprocessorInputs) {
ppFlagsBuilder.addAllIncludes(input.getIncludes());
}
PreprocessorFlags ppFlags = ppFlagsBuilder.build();
// generate C sources with cgo tool (go build writes c files to _obj dir)
ImmutableMap<Path, SourcePath> headers =
CxxDescriptionEnhancer.parseHeaders(
buildTarget,
graphBuilder,
projectFilesystem,
Optional.of(platform.getCxxPlatform()),
args);
HeaderSymlinkTree headerSymlinkTree =
getHeaderSymlinkTree(
buildTarget,
projectFilesystem,
graphBuilder,
platform.getCxxPlatform(),
cxxPreprocessorInputs,
headers);
SourcePathResolverAdapter pathResolver = graphBuilder.getSourcePathResolver();
ImmutableSet.Builder<SourcePath> cxxSourcesFromArg = ImmutableSet.builder();
ImmutableSet.Builder<SourcePath> goSourcesFromArg = ImmutableSet.builder();
for (SourceWithFlags srcWithFlags : args.getSrcs()) {
SourcePath pth = srcWithFlags.getSourcePath();
String ext = Files.getFileExtension(pathResolver.getAbsolutePath(pth).toString());
Optional<CxxSource.Type> srcType = CxxSource.Type.fromExtension(ext);
if (srcType.equals(Optional.of(CxxSource.Type.C))
|| srcType.equals(Optional.of(CxxSource.Type.CXX))) {
cxxSourcesFromArg.add(pth);
} else if (ext.equals("go")) {
goSourcesFromArg.add(pth);
}
}
CGoGenSource genSource =
(CGoGenSource)
graphBuilder.computeIfAbsent(
buildTarget.withAppendedFlavors(InternalFlavor.of("cgo-gen-sources")),
target ->
new CGoGenSource(
target,
projectFilesystem,
graphBuilder,
CxxSourceTypes.getPreprocessor(platform.getCxxPlatform(), CxxSource.Type.C)
.resolve(graphBuilder, target.getTargetConfiguration()),
goSourcesFromArg.build(),
headerSymlinkTree,
cgo,
args.getCgoCompilerFlags(),
ppFlags,
platform
.getCxxPlatform()
.getCpp()
.resolve(graphBuilder, buildTarget.getTargetConfiguration()),
platform));
// generated c files needs to be compiled and linked into a single object
// file (equivalent of (_cgo_.o), includes:
// * _cgo_export.o
// * _cgo_main.o
// * all of the *.cgo2.o
CxxLink cgoBin =
(CxxLink)
graphBuilder.computeIfAbsent(
buildTarget.withAppendedFlavors(InternalFlavor.of("cgo-first-step")),
target ->
nativeBinCompilation(
target,
projectFilesystem,
graphBuilder,
cellRoots,
cxxBuckConfig,
platform.getCxxPlatform(),
args,
new ImmutableList.Builder<BuildRule>()
.add(genSource)
.addAll(allDeps.get(graphBuilder, platform.getCxxPlatform()))
.build(),
new ImmutableMap.Builder<Path, SourcePath>()
.putAll(headers)
.put(
pathResolver
.getAbsolutePath(genSource.getExportHeader())
.getFileName(),
genSource.getExportHeader())
.build(),
new ImmutableList.Builder<SourcePath>()
.addAll(cxxSourcesFromArg.build())
.addAll(genSource.getCFiles())
.addAll(genSource.getCgoFiles())
.build(),
args.getLinkerFlags()));
// generate cgo_import.h with previously generated object file (_cgo.o)
BuildRule cgoImport =
graphBuilder.computeIfAbsent(
buildTarget.withAppendedFlavors(InternalFlavor.of("cgo-gen-import")),
target ->
new CGoGenImport(
target,
projectFilesystem,
graphBuilder,
cgo,
platform,
// take first source file in the list to infer the package
// name via go list
goSourcesFromArg.build().iterator().next(),
Objects.requireNonNull(cgoBin.getSourcePathToOutput())));
// filter out compiled object only for the sources we are interested in
ImmutableList<String> linkableObjectFiles =
Stream.concat(
cxxSourcesFromArg.build().stream()
.map(x -> pathResolver.getAbsolutePath(x).getFileName().toString()),
ImmutableList.of(".cgo2.c", "_cgo_export.c").stream())
.collect(ImmutableList.toImmutableList());
// generate final object file (equivalent of _all.o) which includes:
// * _cgo_export.o
// * all of the *.cgo2.o files
ImmutableList<Arg> cxxArgs =
ImmutableList.<Arg>builder()
.addAll(StringArg.from("-r", "-nostdlib"))
.addAll(
cgoBin.getArgs().stream()
.filter(FileListableLinkerInputArg.class::isInstance)
.map(FileListableLinkerInputArg.class::cast)
.filter(
arg -> {
Path pth = pathResolver.getAbsolutePath(arg.getPath());
String fileName = pth.getFileName().toString();
return pth.toString().contains("cgo-first-step")
&& linkableObjectFiles.stream().anyMatch(x -> fileName.contains(x));
})
.collect(ImmutableList.toImmutableList()))
.build();
CxxLink cgoAllBin =
(CxxLink)
graphBuilder.computeIfAbsent(
buildTarget.withAppendedFlavors(InternalFlavor.of("cgo-second-step")),
target ->
CxxLinkableEnhancer.createCxxLinkableBuildRule(
cellRoots,
cxxBuckConfig,
platform.getCxxPlatform(),
projectFilesystem,
graphBuilder,
target,
BuildTargetPaths.getGenPath(projectFilesystem, target, "%s/_all.o"),
ImmutableMap.of(),
cxxArgs, // collection of selected object files
args.getLinkStyle().orElse(Linker.LinkableDepType.STATIC_PIC),
CxxLinkOptions.of(),
Optional.empty()));
// output (referenced later on by GoCompile) provides:
// * _cgo_gotypes.go
// * _cgo_import.go
// * all of the *.cgo1.go files
//
// the go sources should be appended to sources list and _all.o file should
// be appended to the output binary (pack step)
return graphBuilder.computeIfAbsent(
buildTarget,
target ->
new CGoLibrary(
params
.withDeclaredDeps(
ImmutableSortedSet.<BuildRule>naturalOrder()
.addAll(
graphBuilder.filterBuildRuleInputs(
cgoAllBin.getSourcePathToOutput()))
.addAll(
graphBuilder.filterBuildRuleInputs(
new Builder<SourcePath>()
.addAll(genSource.getGoFiles())
.add(
Objects.requireNonNull(
cgoImport.getSourcePathToOutput()))
.build()))
.build())
.withoutExtraDeps(),
target,
projectFilesystem,
new Builder<SourcePath>()
.addAll(genSource.getGoFiles())
.add(Objects.requireNonNull(cgoImport.getSourcePathToOutput()))
.build(),
Objects.requireNonNull(cgoAllBin.getSourcePathToOutput()),
Objects.requireNonNull(allDeps.get(graphBuilder, platform.getCxxPlatform()))));
}