in src/com/facebook/buck/features/haskell/HaskellGhciRule.java [310:578]
public ImmutableList<Step> getBuildSteps(
BuildContext context, BuildableContext buildableContext) {
SourcePathResolverAdapter resolver = context.getSourcePathResolver();
String name = getBuildTarget().getShortName();
Path dir = getOutputDir();
Path so = resolver.getRelativePath(omnibusSharedObject.getSourcePathToOutput());
Path packagesDir = dir.resolve(name + ".packages");
Path symlinkDir = dir.resolve(HaskellGhciDescription.getSoLibsRelDir(getBuildTarget()));
Path symlinkPreloadDir = dir.resolve(name + ".preload-symlinks");
ImmutableList.Builder<String> compilerFlagsBuilder = ImmutableList.builder();
compilerFlagsBuilder.addAll(compilerFlags);
ImmutableList.Builder<Step> steps = ImmutableList.builder();
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), dir)));
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), symlinkDir)));
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), symlinkPreloadDir)));
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), packagesDir)));
steps.add(CopyStep.forFile(getProjectFilesystem(), so, dir.resolve(so.getFileName())));
symlinkLibs(resolver, symlinkDir, steps, solibs);
symlinkLibs(resolver, symlinkPreloadDir, steps, preloadLibs);
ImmutableSet.Builder<String> pkgdirs = ImmutableSet.builder();
for (HaskellPackage pkg : prebuiltHaskellPackages) {
try {
pkgdirs.add(resolver.getRelativePath(pkg.getPackageDb()).toRealPath().toString());
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
for (HaskellPackage pkg : haskellPackages) {
String pkgname = pkg.getInfo().getName();
Path pkgdir = packagesDir.resolve(pkgname);
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), pkgdir)));
Path pkgDbSrc = resolver.getRelativePath(pkg.getPackageDb());
steps.add(
CopyStep.forDirectory(
getProjectFilesystem(),
pkgDbSrc,
pkgdir,
CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS));
ImmutableSet.Builder<SourcePath> artifacts = ImmutableSet.builder();
artifacts.addAll(pkg.getLibraries());
if (archiveContents == ArchiveContents.THIN) {
// this is required because the .a files above are thin archives,
// they merely point to the .o files via a relative path.
artifacts.addAll(pkg.getObjects());
}
artifacts.addAll(pkg.getInterfaces());
for (SourcePath artifact : artifacts.build()) {
Path source = resolver.getRelativePath(artifact);
Path destination = pkgdir.resolve(source.getParent().getFileName());
steps.add(
MkdirStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), destination)));
steps.add(
CopyStep.forDirectory(
getProjectFilesystem(),
source,
destination,
CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS));
}
pkgdirs.add("${DIR}/" + dir.relativize(pkgdir.resolve(pkgDbSrc.getFileName())));
}
ImmutableSet.Builder<String> exposedPkgs = ImmutableSet.builder();
for (HaskellPackage pkg : firstOrderHaskellPackages) {
exposedPkgs.add(String.format("%s-%s", pkg.getInfo().getName(), pkg.getInfo().getVersion()));
}
// iserv script
Optional<Path> iservScript = Optional.empty();
if (!preloadLibs.isEmpty()) {
iservScript = Optional.of(dir.resolve("iserv"));
compilerFlagsBuilder.add("-fexternal-interpreter");
steps.add(
new AbstractExecutionStep("ghci_iserv_wrapper") {
@Override
public StepExecutionResult execute(ExecutionContext context) throws IOException {
String template;
template = new String(Files.readAllBytes(ghciIservScriptTemplate), Charsets.UTF_8);
ST st = new ST(template);
ImmutableSet.Builder<String> preloadLibrariesB = ImmutableSet.builder();
for (String libPath : preloadLibs.keySet()) {
preloadLibrariesB.add(
"${DIR}/" + dir.relativize(symlinkPreloadDir.resolve(libPath)));
}
ImmutableSet<String> preloadLibraries = preloadLibrariesB.build();
st.add("name", name + "-iserv");
st.add("preload_libs", Joiner.on(':').join(preloadLibraries));
if (enableProfiling) {
st.add("ghci_iserv_path", ghciIServProf.toRealPath().toString());
} else {
st.add("ghci_iserv_path", ghciIServ.toRealPath().toString());
}
Path actualIserv = dir.resolve("iserv");
if (enableProfiling) {
actualIserv = dir.resolve("iserv-prof");
}
return new WriteFileStep(
getProjectFilesystem(),
Objects.requireNonNull(st.render()),
actualIserv, /* executable */
true)
.execute(context);
}
});
}
// .ghci file
StringBuilder startGhciContents = new StringBuilder();
if (iservScript.isPresent()) {
// Need to unset preloaded deps for `iserv`
startGhciContents.append("System.Environment.unsetEnv \"LD_PRELOAD\"\n");
}
startGhciContents.append(":set ");
startGhciContents.append(
Joiner.on(' ')
.join(
ImmutableList.<String>builder()
.addAll(
MoreIterables.zipAndConcat(
Iterables.cycle("-package"), exposedPkgs.build()))
.build()));
if (ghciInit.isPresent()) {
try {
startGhciContents.append('\n');
List<String> lines =
Files.readAllLines(resolver.getRelativePath(ghciInit.get()), StandardCharsets.UTF_8);
startGhciContents.append(Joiner.on('\n').join(lines));
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
Path startGhci = dir.resolve("start.ghci");
steps.add(
new WriteFileStep(
getProjectFilesystem(),
startGhciContents.toString(),
startGhci,
/* executable */ false));
// ghciBinDep
ImmutableList.Builder<String> srcpaths = ImmutableList.builder();
for (SourcePath sp : srcs.getSourcePaths()) {
srcpaths.add(resolver.getRelativePath(sp).toString());
}
String ghcPath = null;
try {
if (ghciBinDep.isPresent()) {
Path binDir = dir.resolve(name + ".bin");
Path bin = binDir.resolve("ghci");
SourcePath sp = ghciBinDep.get();
steps.addAll(
MakeCleanDirectoryStep.of(
BuildCellRelativePath.fromCellRelativePath(
context.getBuildCellRootPath(), getProjectFilesystem(), binDir)));
steps.add(CopyStep.forFile(getProjectFilesystem(), resolver.getRelativePath(sp), bin));
ghcPath = "${DIR}/" + dir.relativize(bin) + " -B" + ghciLib.toRealPath();
} else {
ghcPath = ghciGhc.toRealPath().toString();
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
String pkgdbs =
Joiner.on(' ')
.join(
ImmutableList.<String>builder()
.addAll(
MoreIterables.zipAndConcat(Iterables.cycle("-package-db"), pkgdirs.build()))
.build());
String exposed =
Joiner.on(' ')
.join(
ImmutableList.<String>builder()
.addAll(
MoreIterables.zipAndConcat(
Iterables.cycle("-expose-package"), exposedPkgs.build()))
.build());
if (enableProfiling) {
compilerFlagsBuilder.addAll(HaskellDescriptionUtils.PROF_FLAGS);
}
compilerFlagsBuilder.addAll(HaskellDescriptionUtils.PIC_FLAGS);
String ghc = ghcPath;
ImmutableMap.Builder<String, String> templateArgs = ImmutableMap.builder();
try {
templateArgs.put("name", name);
templateArgs.put("start_ghci", dir.relativize(startGhci).toString());
templateArgs.put("exposed_packages", exposed);
templateArgs.put("package_dbs", pkgdbs);
templateArgs.put("compiler_flags", Joiner.on(' ').join(compilerFlagsBuilder.build()));
templateArgs.put("srcs", Joiner.on(' ').join(srcpaths.build()));
templateArgs.put("squashed_so", dir.relativize(dir.resolve(so.getFileName())).toString());
templateArgs.put("binutils_path", ghciBinutils.toRealPath().toString());
// ghc_path points to the ghc tool for this binary
templateArgs.put("ghc_path", ghciGhc.toRealPath().toString());
// user_ghci_path points to user-defined ghci binary, which can be eithe
// the same as ghc_path, or a haskell_binary itself compiled during this
// buck run.
templateArgs.put("user_ghci_path", ghc);
templateArgs.put("cxx_path", ghciCxx.toRealPath().toString());
templateArgs.put("cc_path", ghciCc.toRealPath().toString());
templateArgs.put("cpp_path", ghciCpp.toRealPath().toString());
templateArgs.put("ghc_pkg_path", ghciPackager.toRealPath().toString());
if (iservScript.isPresent()) {
templateArgs.put("iserv_path", dir.relativize(iservScript.get()).toString());
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
Path script = scriptPath();
steps.add(
new StringTemplateStep(
ghciScriptTemplate, getProjectFilesystem(), script, templateArgs.build()));
steps.add(new MakeExecutableStep(getProjectFilesystem(), script));
for (SourcePath s : extraScriptTemplates) {
Path templateAbsPath = resolver.getAbsolutePath(s);
Path extraScript = dir.resolve(templateAbsPath.getFileName());
steps.add(
new StringTemplateStep(
templateAbsPath, getProjectFilesystem(), extraScript, templateArgs.build()));
steps.add(new MakeExecutableStep(getProjectFilesystem(), extraScript));
}
buildableContext.recordArtifact(dir);
return steps.build();
}