Example usage for com.google.common.collect Iterables cycle

List of usage examples for com.google.common.collect Iterables cycle

Introduction

In this page you can find the example usage for com.google.common.collect Iterables cycle.

Prototype

public static <T> Iterable<T> cycle(T... elements) 

Source Link

Document

Returns an iterable whose iterators cycle indefinitely over the provided elements.

Usage

From source file:com.facebook.buck.haskell.HaskellCompileRule.java

/**
 * @return the arguments to pass to the compiler to build against package dependencies.
 *///from   w w w . ja v a2  s.c o  m
private Iterable<String> getPackageArgs() {
    Set<String> packageDbs = new TreeSet<>();
    Set<String> hidden = new TreeSet<>();
    Set<String> exposed = new TreeSet<>();

    for (HaskellPackage haskellPackage : packages.values()) {
        packageDbs.add(getResolver().getAbsolutePath(haskellPackage.getPackageDb()).toString());
        hidden.add(String.format("%s-%s", haskellPackage.getInfo().getName(),
                haskellPackage.getInfo().getVersion()));
    }

    for (HaskellPackage haskellPackage : exposedPackages.values()) {
        packageDbs.add(getResolver().getAbsolutePath(haskellPackage.getPackageDb()).toString());
        exposed.add(String.format("%s-%s", haskellPackage.getInfo().getName(),
                haskellPackage.getInfo().getVersion()));
    }

    // We add all package DBs, and explicit expose or hide packages depending on whether they are
    // exposed or not.  This allows us to support setups that either add `-hide-all-packages` or
    // not.
    return ImmutableList.<String>builder()
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-package-db"), packageDbs))
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-package"), exposed))
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-hide-package"), hidden)).build();
}

From source file:com.facebook.buck.features.haskell.HaskellBinaryDescription.java

@Override
public BuildRule createBuildRule(BuildRuleCreationContextWithTargetGraph context, BuildTarget buildTarget,
        BuildRuleParams params, HaskellBinaryDescriptionArg args) {

    ProjectFilesystem projectFilesystem = context.getProjectFilesystem();
    CellPathResolver cellRoots = context.getCellPathResolver();
    HaskellPlatform platform = getPlatform(buildTarget, args);

    ActionGraphBuilder graphBuilder = context.getActionGraphBuilder();
    Optional<Type> type = BINARY_TYPE.getValue(buildTarget);
    // Handle #ghci flavor
    if (type.isPresent() && type.get() == Type.GHCI) {
        return HaskellDescriptionUtils.requireGhciRule(buildTarget, projectFilesystem, params, cellRoots,
                graphBuilder, platform, cxxBuckConfig, args.getDeps(), args.getPlatformDeps(), args.getSrcs(),
                args.getGhciPreloadDeps(), args.getGhciPlatformPreloadDeps(), args.getCompilerFlags(),
                Optional.empty(), Optional.empty(), ImmutableList.of(), args.isEnableProfiling());
    }/*www.  jav a2s . c o m*/

    SourcePathRuleFinder ruleFinder = new SourcePathRuleFinder(graphBuilder);
    SourcePathResolver pathResolver = DefaultSourcePathResolver.from(ruleFinder);
    Linker.LinkableDepType depType = getLinkStyle(args, type);

    // The target to use for the link rule.
    BuildTarget binaryTarget = buildTarget.withFlavors(InternalFlavor.of("binary"));

    // Maintain backwards compatibility to ease upgrade flows.
    if (platform.shouldUsedOldBinaryOutputLocation().orElse(true)) {
        binaryTarget = binaryTarget.withAppendedFlavors(platform.getFlavor());
    }

    ImmutableSet.Builder<BuildRule> depsBuilder = ImmutableSet.builder();

    depsBuilder.addAll(CxxDeps.builder().addDeps(args.getDeps()).addPlatformDeps(args.getPlatformDeps()).build()
            .get(graphBuilder, platform.getCxxPlatform()));

    ImmutableList<BuildRule> depQueryDeps = args.getDepsQuery()
            .map(query -> Objects.requireNonNull(query.getResolvedQuery()).stream().map(graphBuilder::getRule)
                    .filter(NativeLinkable.class::isInstance))
            .orElse(Stream.of()).collect(ImmutableList.toImmutableList());
    depsBuilder.addAll(depQueryDeps);
    ImmutableSet<BuildRule> deps = depsBuilder.build();

    // Inputs we'll be linking (archives, objects, etc.)
    ImmutableList.Builder<Arg> linkInputsBuilder = ImmutableList.builder();
    // Additional linker flags passed to the Haskell linker
    ImmutableList.Builder<Arg> linkFlagsBuilder = ImmutableList.builder();

    CommandTool.Builder executableBuilder = new CommandTool.Builder();

    // Add the binary as the first argument.
    executableBuilder.addArg(SourcePathArg.of(DefaultBuildTargetSourcePath.of(binaryTarget)));

    Path outputDir = BuildTargetPaths.getGenPath(projectFilesystem, binaryTarget, "%s").getParent();
    Path outputPath = outputDir.resolve(binaryTarget.getShortName());

    Path absBinaryDir = buildTarget.getCellPath().resolve(outputDir);

    // Special handling for dynamically linked binaries.
    if (depType == Linker.LinkableDepType.SHARED) {

        // Create a symlink tree with for all shared libraries needed by this binary.
        SymlinkTree sharedLibraries = graphBuilder.addToIndex(
                CxxDescriptionEnhancer.createSharedLibrarySymlinkTree(buildTarget, projectFilesystem,
                        graphBuilder, ruleFinder, platform.getCxxPlatform(), deps, r -> Optional.empty()));

        // Embed a origin-relative library path into the binary so it can find the shared libraries.
        // The shared libraries root is absolute. Also need an absolute path to the linkOutput
        linkFlagsBuilder.addAll(StringArg.from(MoreIterables.zipAndConcat(Iterables.cycle("-optl"),
                Linkers.iXlinker("-rpath",
                        String.format("%s/%s", platform.getCxxPlatform().getLd().resolve(graphBuilder).origin(),
                                absBinaryDir.relativize(sharedLibraries.getRoot()).toString())))));

        // Add all the shared libraries and the symlink tree as inputs to the tool that represents
        // this binary, so that users can attach the proper deps.
        executableBuilder.addNonHashableInput(sharedLibraries.getRootSourcePath());
        executableBuilder.addInputs(sharedLibraries.getLinks().values());
    }

    // Add in linker flags.
    linkFlagsBuilder.addAll(ImmutableList.copyOf(Iterables.transform(args.getLinkerFlags(),
            f -> CxxDescriptionEnhancer.toStringWithMacrosArgs(buildTarget, cellRoots, graphBuilder,
                    platform.getCxxPlatform(), f))));

    // Generate the compile rule and add its objects to the link.
    HaskellCompileRule compileRule = graphBuilder.addToIndex(HaskellDescriptionUtils.requireCompileRule(
            buildTarget, projectFilesystem, params, graphBuilder, ruleFinder,
            RichStream.from(deps)
                    .filter(dep -> dep instanceof HaskellCompileDep || dep instanceof CxxPreprocessorDep)
                    .toImmutableSet(),
            platform, depType, args.isEnableProfiling(), args.getMain(), Optional.empty(),
            args.getCompilerFlags(), HaskellSources.from(buildTarget, graphBuilder, pathResolver, ruleFinder,
                    platform, "srcs", args.getSrcs())));
    linkInputsBuilder.addAll(SourcePathArg.from(compileRule.getObjects()));

    ImmutableList<Arg> linkInputs = linkInputsBuilder.build();
    ImmutableList<Arg> linkFlags = linkFlagsBuilder.build();

    CommandTool executable = executableBuilder.build();
    HaskellLinkRule linkRule = HaskellDescriptionUtils.createLinkRule(binaryTarget, projectFilesystem, params,
            graphBuilder, ruleFinder, platform, Linker.LinkType.EXECUTABLE, linkFlags, linkInputs,
            RichStream.from(deps).filter(NativeLinkable.class).toImmutableList(),
            args.getLinkDepsQueryWhole()
                    ? RichStream.from(depQueryDeps).map(BuildRule::getBuildTarget).toImmutableSet()
                    : ImmutableSet.of(),
            depType, outputPath, Optional.empty(), args.isEnableProfiling());

    return new HaskellBinary(buildTarget, projectFilesystem, params.copyAppendingExtraDeps(linkRule), deps,
            executable, linkRule.getSourcePathToOutput());
}

From source file:com.facebook.buck.haskell.HaskellCompileRule.java

private Iterable<String> getPreprocessorFlags() {
    CxxToolFlags cxxToolFlags = ppFlags.toToolFlags(getResolver(), PathShortener.identity(),
            CxxDescriptionEnhancer.frameworkPathToSearchPath(cxxPlatform, getResolver()), preprocessor,
            /* pch */ Optional.empty());
    return MoreIterables.zipAndConcat(Iterables.cycle("-optP"), cxxToolFlags.getAllFlags());
}

From source file:com.facebook.buck.features.haskell.HaskellCompileRule.java

/** @return the arguments to pass to the compiler to build against package dependencies. */
private Iterable<String> getPackageArgs(SourcePathResolver resolver) {
    Set<String> packageDbs = new TreeSet<>();
    Set<String> hidden = new TreeSet<>();
    Set<String> exposed = new TreeSet<>();

    for (HaskellPackage haskellPackage : packages.values()) {
        packageDbs.add(resolver.getAbsolutePath(haskellPackage.getPackageDb()).toString());
        hidden.add(String.format("%s-%s", haskellPackage.getInfo().getName(),
                haskellPackage.getInfo().getVersion()));
    }/*  www  .j  av  a2s .c o  m*/

    for (HaskellPackage haskellPackage : exposedPackages.values()) {
        packageDbs.add(resolver.getAbsolutePath(haskellPackage.getPackageDb()).toString());
        exposed.add(String.format("%s-%s", haskellPackage.getInfo().getName(),
                haskellPackage.getInfo().getVersion()));
    }

    // We add all package DBs, and explicit expose or hide packages depending on whether they are
    // exposed or not.  This allows us to support setups that either add `-hide-all-packages` or
    // not.
    return ImmutableList.<String>builder()
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-package-db"), packageDbs))
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-package"), exposed))
            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-hide-package"), hidden)).build();
}

From source file:com.facebook.buck.features.haskell.HaskellCompileRule.java

private Iterable<String> getPreprocessorFlags(SourcePathResolver resolver) {
    CxxToolFlags cxxToolFlags = ppFlags.toToolFlags(resolver, PathShortener.identity(),
            CxxDescriptionEnhancer.frameworkPathToSearchPath(cxxPlatform, resolver), preprocessor,
            /* pch */ Optional.empty());
    return MoreIterables.zipAndConcat(Iterables.cycle("-optP"),
            Arg.stringify(cxxToolFlags.getAllFlags(), resolver));
}

From source file:com.eucalyptus.util.async.Futures.java

/**
 * TODO:GUAVA: remove and use the method available in Guava 10 
 *///from  w  w  w. j a  va  2 s  .  c  o m
public static <R> CheckedListenableFuture<List<R>> allAsList(final List<CheckedListenableFuture<R>> futures) {
    final GenericCheckedListenableFuture<List<R>> combined = new GenericCheckedListenableFuture<List<R>>();
    final List<R> resultList = Lists.newArrayListWithCapacity(futures.size());
    Iterables.addAll(resultList, Iterables.limit(Iterables.cycle((R) null), futures.size()));
    final AtomicInteger completionCountdown = new AtomicInteger(futures.size());
    for (int i = 0; i < futures.size(); i++) {
        final int resultIndex = i;
        final CheckedListenableFuture<R> future = futures.get(i);
        future.addListener(new Runnable() {
            @Override
            public void run() {
                try {
                    resultList.set(resultIndex, future.get());
                } catch (final ExecutionException e) {
                    combined.setException(e.getCause());
                } catch (CancellationException e) {
                    combined.cancel(false);
                } catch (InterruptedException e) {
                    // complete so can't happen
                }
                if (completionCountdown.decrementAndGet() == 0) {
                    combined.set(resultList);
                }
            }
        });
    }

    return combined;
}

From source file:com.facebook.buck.features.haskell.HaskellDescriptionUtils.java

/**
 * Create a Haskell link rule that links the given inputs to a executable or shared library and
 * pulls in transitive native linkable deps from the given dep roots.
 *///from  w w  w.  j a v  a  2s .  c  o  m
public static HaskellLinkRule createLinkRule(BuildTarget target, ProjectFilesystem projectFilesystem,
        BuildRuleParams baseParams, ActionGraphBuilder graphBuilder, SourcePathRuleFinder ruleFinder,
        HaskellPlatform platform, Linker.LinkType linkType, ImmutableList<Arg> linkerFlags,
        Iterable<Arg> linkerInputs, Iterable<? extends NativeLinkable> deps,
        ImmutableSet<BuildTarget> linkWholeDeps, Linker.LinkableDepType depType, Path outputPath,
        Optional<String> soname, boolean hsProfile) {

    Tool linker = platform.getLinker().resolve(graphBuilder);

    ImmutableList.Builder<Arg> linkerArgsBuilder = ImmutableList.builder();
    ImmutableList.Builder<Arg> argsBuilder = ImmutableList.builder();

    // Add the base flags from the `.buckconfig` first.
    argsBuilder.addAll(StringArg.from(platform.getLinkerFlags()));

    // Pass in the appropriate flags to link a shared library.
    if (linkType.equals(Linker.LinkType.SHARED)) {
        argsBuilder.addAll(StringArg.from("-shared", "-dynamic"));
        soname.ifPresent(
                name -> argsBuilder.addAll(StringArg.from(MoreIterables.zipAndConcat(Iterables.cycle("-optl"),
                        platform.getCxxPlatform().getLd().resolve(graphBuilder).soname(name)))));
    }

    // Add in extra flags passed into this function.
    argsBuilder.addAll(linkerFlags);

    // We pass in the linker inputs and all native linkable deps by prefixing with `-optl` so that
    // the args go straight to the linker, and preserve their order.
    linkerArgsBuilder.addAll(linkerInputs);
    for (NativeLinkable nativeLinkable : NativeLinkables.getNativeLinkables(platform.getCxxPlatform(),
            graphBuilder, deps, depType)) {
        NativeLinkable.Linkage link = nativeLinkable.getPreferredLinkage(platform.getCxxPlatform(),
                graphBuilder);
        NativeLinkableInput input = nativeLinkable.getNativeLinkableInput(platform.getCxxPlatform(),
                NativeLinkables.getLinkStyle(link, depType),
                linkWholeDeps.contains(nativeLinkable.getBuildTarget()), graphBuilder);
        linkerArgsBuilder.addAll(input.getArgs());
    }

    // Since we use `-optl` to pass all linker inputs directly to the linker, the haskell linker
    // will complain about not having any input files.  So, create a dummy archive with an empty
    // module and pass that in normally to work around this.
    BuildTarget emptyModuleTarget = target.withAppendedFlavors(InternalFlavor.of("empty-module"));
    WriteFile emptyModule = graphBuilder
            .addToIndex(new WriteFile(emptyModuleTarget, projectFilesystem, "module Unused where",
                    BuildTargetPaths.getGenPath(projectFilesystem, emptyModuleTarget, "%s/Unused.hs"),
                    /* executable */ false));
    HaskellCompileRule emptyCompiledModule = graphBuilder.addToIndex(createCompileRule(
            target.withAppendedFlavors(InternalFlavor.of("empty-compiled-module")), projectFilesystem,
            baseParams, graphBuilder, ruleFinder,
            // TODO(agallagher): We shouldn't need any deps to compile an empty module, but ghc
            // implicitly tries to load the prelude and in some setups this is provided via a
            // Buck dependency.
            RichStream.from(deps).filter(BuildRule.class).toImmutableSortedSet(Ordering.natural()), platform,
            depType, hsProfile, Optional.empty(), Optional.empty(), ImmutableList.of(),
            HaskellSources.builder().putModuleMap("Unused", emptyModule.getSourcePathToOutput()).build()));
    BuildTarget emptyArchiveTarget = target.withAppendedFlavors(InternalFlavor.of("empty-archive"));
    Archive emptyArchive = graphBuilder.addToIndex(Archive.from(emptyArchiveTarget, projectFilesystem,
            graphBuilder, ruleFinder, platform.getCxxPlatform(),
            BuildTargetPaths.getGenPath(projectFilesystem, emptyArchiveTarget, "%s/libempty.a"),
            emptyCompiledModule.getObjects(), /* cacheable */ true));
    argsBuilder.add(SourcePathArg.of(emptyArchive.getSourcePathToOutput()));

    ImmutableList<Arg> args = argsBuilder.build();
    ImmutableList<Arg> linkerArgs = linkerArgsBuilder.build();

    return graphBuilder.addToIndex(new HaskellLinkRule(target, projectFilesystem, baseParams
            .withDeclaredDeps(ImmutableSortedSet.<BuildRule>naturalOrder()
                    .addAll(BuildableSupport.getDepsCollection(linker, ruleFinder))
                    .addAll(Stream.of(args, linkerArgs).flatMap(Collection::stream)
                            .flatMap(arg -> BuildableSupport.getDeps(arg, ruleFinder)).iterator())
                    .build())
            .withoutExtraDeps(), linker, outputPath, args, linkerArgs, platform.shouldCacheLinks()));
}

From source file:com.facebook.buck.haskell.HaskellCompileRule.java

@Override
public ImmutableList<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext) {
    buildableContext.recordArtifact(getObjectDir());
    buildableContext.recordArtifact(getInterfaceDir());
    buildableContext.recordArtifact(getStubDir());
    return ImmutableList.of(new MakeCleanDirectoryStep(getProjectFilesystem(), getObjectDir()),
            new MakeCleanDirectoryStep(getProjectFilesystem(), getInterfaceDir()),
            new MakeCleanDirectoryStep(getProjectFilesystem(), getStubDir()),
            new ShellStep(getProjectFilesystem().getRootPath()) {

                @Override/*from  w  w w.j a  v a 2 s . co  m*/
                public ImmutableMap<String, String> getEnvironmentVariables(ExecutionContext context) {
                    return ImmutableMap.<String, String>builder().putAll(super.getEnvironmentVariables(context))
                            .putAll(compiler.getEnvironment()).build();
                }

                @Override
                protected ImmutableList<String> getShellCommandInternal(ExecutionContext context) {
                    return ImmutableList.<String>builder().addAll(compiler.getCommandPrefix(getResolver()))
                            .addAll(flags).add("-no-link")
                            .addAll(picType == CxxSourceRuleFactory.PicType.PIC
                                    ? ImmutableList.of("-dynamic", "-fPIC", "-hisuf", "dyn_hi")
                                    : ImmutableList.of())
                            .addAll(MoreIterables.zipAndConcat(Iterables.cycle("-main-is"),
                                    OptionalCompat.asSet(main)))
                            .addAll(getPackageNameArgs()).addAll(getPreprocessorFlags())
                            .add("-odir", getProjectFilesystem().resolve(getObjectDir()).toString())
                            .add("-hidir", getProjectFilesystem().resolve(getInterfaceDir()).toString())
                            .add("-stubdir", getProjectFilesystem().resolve(getStubDir()).toString())
                            .add("-i" + includes.stream().map(getResolver()::getAbsolutePath)
                                    .map(Object::toString).collect(Collectors.joining(":")))
                            .addAll(getPackageArgs()).addAll(sources.getSourcePaths().stream()
                                    .map(getResolver()::getAbsolutePath).map(Object::toString).iterator())
                            .build();
                }

                @Override
                public String getShortName() {
                    return "haskell-compile";
                }

            });
}

From source file:com.facebook.buck.ocaml.OCamlBuildContext.java

private static ImmutableList<String> addPrefix(String prefix, Iterable<String> flags) {
    return ImmutableList.copyOf(MoreIterables.zipAndConcat(Iterables.cycle(prefix), flags));
}

From source file:com.facebook.buck.haskell.HaskellGhciRule.java

@Override
public ImmutableList<Step> getBuildSteps(BuildContext context, BuildableContext buildableContext) {

    SourcePathResolver resolver = context.getSourcePathResolver();

    String name = getBuildTarget().getShortName();
    Path dir = getOutputDir();/* www  .ja va2s. c  om*/
    Path so = resolver.getRelativePath(omnibusSharedObject.getSourcePathToOutput());
    Path packagesDir = dir.resolve(name + ".packages");
    Path symlinkDir = dir.resolve(name + ".so-symlinks");

    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(), packagesDir)));

    steps.add(CopyStep.forFile(getProjectFilesystem(), so, dir.resolve(so.getFileName())));

    try {
        for (Map.Entry<String, SourcePath> ent : solibs.entrySet()) {
            Path src = resolver.getRelativePath(ent.getValue()).toRealPath();
            Path dest = symlinkDir.resolve(ent.getKey());
            steps.add(SymlinkFileStep.builder().setFilesystem(getProjectFilesystem()).setExistingFile(src)
                    .setDesiredLink(dest).build());
        }
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }

    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<Path> artifacts = ImmutableSet.builder();
        for (SourcePath lib : pkg.getLibraries()) {
            artifacts.add(resolver.getRelativePath(lib).getParent());
        }

        // this is required because the .a files above are thin archives,
        // they merely point to the .o files via a relative path.
        for (SourcePath obj : pkg.getObjects()) {
            artifacts.add(resolver.getRelativePath(obj).getParent());
        }

        for (SourcePath iface : pkg.getInterfaces()) {
            artifacts.add(resolver.getRelativePath(iface).getParent());
        }

        for (Path artifact : artifacts.build()) {
            steps.add(CopyStep.forDirectory(getProjectFilesystem(), artifact, pkgdir,
                    CopyStep.DirectoryMode.DIRECTORY_AND_CONTENTS));
        }

        pkgdirs.add("${DIR}/" + dir.relativize(pkgdir.resolve(pkgDbSrc.getFileName())).toString());
    }

    ImmutableSet.Builder<String> exposedPkgs = ImmutableSet.builder();
    for (HaskellPackage pkg : firstOrderHaskellPackages) {
        exposedPkgs.add(String.format("%s-%s", pkg.getInfo().getName(), pkg.getInfo().getVersion()));
    }

    StringBuilder startGhciContents = new StringBuilder();
    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));

    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");
            BuildRule rule = buildRuleResolver.getRule(ghciBinDep.get());
            SourcePath sp = rule.getSourcePathToOutput();

            steps.addAll(MakeCleanDirectoryStep.of(BuildCellRelativePath
                    .fromCellRelativePath(context.getBuildCellRootPath(), getProjectFilesystem(), binDir)));

            steps.add(CopyStep.forFile(getProjectFilesystem(), resolver.getRelativePath(sp), bin));

            ghcPath = "${DIR}/" + dir.relativize(bin).toString() + " -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) {
        compilerFlags = ImmutableList
                .copyOf(Iterables.concat(compilerFlags, HaskellDescriptionUtils.PROF_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("ld_library_path", dir.relativize(symlinkDir).toString());
        templateArgs.put("exposed_packages", exposed);
        templateArgs.put("package_dbs", pkgdbs);
        templateArgs.put("compiler_flags", Joiner.on(' ').join(compilerFlags));
        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());
        templateArgs.put("ghc_path", ghc);
        templateArgs.put("cxx_path", ghciCxx.toRealPath().toString());
        templateArgs.put("cc_path", ghciCc.toRealPath().toString());
        templateArgs.put("cpp_path", ghciCpp.toRealPath().toString());
    } catch (IOException ex) {
        throw new RuntimeException(ex);
    }

    Path script = dir.resolve(name);
    steps.add(new StringTemplateStep(ghciScriptTemplate, getProjectFilesystem(), script, templateArgs.build()));
    steps.add(new MakeExecutableStep(getProjectFilesystem(), script));
    return steps.build();
}