How can I run GHCi against a compiled package? - haskell

I should really know this by now, but I don't. I'm often working on a Cabal-based package and have just run a successful cabal build. Now I want to try some things out in GHCi. If I run cabal repl, then GHC recompiles the whole package into bytecode and runs it in the interpreter. Not what I want at all! If I were just running GHCi directly, I'd use something like -O -fobject-code, but that won't give me the package context. I just want "Give me a repl with the package as it's been compiled, compiling additional things only as necessary." How do I do it?

I don't know the right way, but I do know a workaround that can sometimes be useful. If the thing you care about is a library component, you can ask for a repl for an executable component.

I believe --repl-options -fobject-code kind of does what you want:
cabal repl --repl-options -fobject-code --repl-options -O --builddir dist-repl
This will give you incremental building of compiled code as you work in GHCi. Caveats:
dist-repl is an alternative directory for the -fobject-code build objects. As of cabal 3.6.2.0 at least, trying to reuse the regular output from cabal build leads to some unnecessary rebuilds and other strange behaviour, as reported at cabal issue #3565. That being so, it's better to compromise and use --builddir to keep a separate set of build objects. Note that cabal clean accepts the --builddir option just fine.
Setting the optimisation level explicitly is necessary, as otherwise the default -O0 from cabal repl will override your package setting.

Related

Two cabal packages in a cabal.project and nix-building both (a lib and its example prgs)

I have a haskell lib X having the following file-structure:
X/src/libxfiles.hs
X/default.nix
X/shell.nix
X/libx.nix
X/libx.cabal
X/cabal.project
and
X/example/lib/exampleCommon.hs
X/example/ex1/main.hs
X/example/ex2/main.hs
X/example/example.cabal
cabal.project points to libx.cabal and to example/example.cabal and cabal new-build all works inside nix-shell. The required haskell packages for libx library and example-programs are introduced in the libx.nix -file.
Why this structure? Since the example programs have 99% common code and only a couple of lines that are ui-dependend (webkit2gtk and such). Earlier version had flags and CPP inside the main of example and nix-build produced the lib and example prg in result-directory. On this new setup, the cabal new-build works ok when the compiler is ghc and my aim is to produce programs with ghc.
Earlier nix-build build the lib and one of its example programs with ghcjs.
At the moment, nix-build makes only the lib. Is it somehow possible to tell in the libx.nix or in the default.nix to also build one of the example-programs, say ex1? That is, to tell for the build process to cabal new-build ex1 and then install the result just like it installs the lib.
To use ghcjs, to build the ex1 that is targeted to ghcjs, it is possible to nix-shell --argstr "compiler" "ghcjs" and then cabal new-configure --ghcjs etc. (So, outside nix-shell, the nix-build -command is not doing all I'd like it do.)
Is it required to make a nix-files into the example-directory? Somehow this does not sound that appealing as the required modules are already given in libx.nix. That is, should I do something like in the answer to how to get cabal and nix work together?
Or is there a haskell package in github having similar structure that could work as an example?
Ideal solution would be that nix-build would build the lib and all its example programs. That would require the use of different building tools (ghc and ghcjs). Thus, maybe the question is, how to make a nix-setup for a multipackage cabal-project where individual packages need different environments including the compilation tools. On ideal world, the default nix-build would build all, and user could parameterize the nix-build to build the chosen example or examples etc.
It appears that the discussions in
cabal issue 4646 and in cabal2nix issue 286 are possibly related.

nix-shell as #! interpreter for runghc

I'm trying to use nix-shell as a #! wrapper for runghc, as suggested in the manpage. But it cannot find the libraries. Given the following example, cut-down from the manpage
#! /usr/bin/env nix-shell
#! nix-shell -i runghc -p haskellPackages.HTTP
import Network.HTTP
main = return ()
I get the following result:
[~:0]$ ./nixshelltest
nixshelltest:4:1: error:
Failed to load interface for ‘Network.HTTP’
Use -v to see a list of the files searched for.
[~:1]$
to my mind, that's exactly what nix-shell -p is to avoid.
Am I doing something wrong, missing the point, or is there a bug? This is both on a nixOS 17.03 host, and also a host running nix 17.09 on top of Ubuntu.
Thanks,
The environment that you're using to run the script is missing a step. It's got a GHC and a HTTP package, but the compiler doesn't know about the package.
The way GHC and library packages work in nix might be a little "inside out" from what you're expecting. You actually need to install a compiler that "depends on" all of the libraries you want, rather than simply installing the compiler and the library separately. The reason is that GHC is designed to have library packages added by modifying the file tree where GHC is installed. On a mutable file system with only a single system GHC install you would just modify GHC whenever a library was installed, but nix can't. Nix has to be able to install a frozen GHC that never changes, and potentially many of them.
So what happens instead is that you install a tiny wrapper which depends on the both the underlying "raw" GHC install and all of the libraries that you want to use. The wrapper then acts like an install of GHC that had those libraries registered, without actually needing to duplicate an entire GHC install. When you just install a library package on its own it just sits there inert, without any GHC being able to find it just by it existing.
In fact, the script you've shown here doesn't actually specify that it should have a compiler installed at all; it just asks for the HTTP library. When I tried your script I got command not found: runghc. The runghc is only working on your system because it happened to already be in your path when you ran this (perhaps because you have GHC installed in your profile?), and that GHC wasn't installed with the HTTP package and so can't see it. The nix-shell adding just the library to the environment doesn't help.
What you need to do instead is use this line:
#! nix-shell -i runghc -p "ghc.withPackages (ps: [ ps.HTTP ])"
You're not installing either ghc or HTTP directly; instead the ghc.withPackages function computes a nix package that installs a GHC wrapper that knows about the HTTP Haskell package. Under the hood this depends on a "raw" GHC with no additional libraries, and also on the HTTP library and will cause those to be installed too.
If you use lots of different Haskell environments (possibly via nix-shell scripts like this that each need a different set of libraries), then you will end up with a unique withPackages wrapper installed on your system for each combination of libraries you ever use. But that's okay because the wrappers themselves are tiny, and nix is able to share and reuse the underlying GHCs and library packages between all of those environments.

Where do I find (and run) an executable compiled with a cabal sandbox?

I'm compiling my myProgram.lhs with the use of a cabal sandbox (set up with cabal sandbox init). I'm using a simplest approach I've come up with:
cabal exec -- ghc myProgram
or (having a rule in Makefile)
cabal exec -- make myProgram
After that, in my source directory, appears myProgram.o, but not the executable myProgram.
How do I run the resulting program?
cabal exec -- ./myProgram
doesn't work.
Now, I've come up with a simplest approach to test it:
cabal exec -- runghc myProgram.lhs
but I don't like this.
Do you know where the resulting executable is?
(I haven't created any cabal file for my project yet. I simply used to compile the program with bare ghc and test it, then--when I needed custom dependencies--I set up the cabal sanbox and installed the dependencies manually there.)
This didn't actually look like a problem of cabal exec, and it wasn't!
My history
Simultaneously with starting to use the cabal sandbox, I explicitly gave a custom name to my module in the source file (myProgram.lhs). And in such case just a bare ghc (without cabal exec) wouldn't generate the executable, too, as answered in Cabal output is redirected but not generated. (I simply couldn't test the bare ghc command, because I had the dependencies in the sandbox, so my module wouldn't compile.)
Explanation
Explanation quoted from that Q&A:
I get the warning
output was redirected with -o, but no output will be generated because there is no main module.
A quote from The Haskell 98 Report:
A Haskell program is a collection of modules, one of which, by convention, must be called Main and must export the value main.
The solution
A solution is to add -main-is MyProgram.main to ghc opts. Then it generates the executable.
./myProgram simply appears in my source directory now, no matter whether I call
ghc -main-is MyProgram.main myProgram
or
cabal exec -- ghc -main-is MyProgram.main myProgram

how to reuse cabal compiled modules when using ghci

I have a fairly large haskell project, and running ghci on some files can require compiling dozens or hundreds of modules before it gets to a prompt, which can take a number of minutes. I'm using cabal, and so I generally have already compiled object files under dist/. But ghci only looks for .o files next to the source .hs files; it does not know about cabal's dist/. Is there any simple and good way to make ghci load those object files rather than recompiling everything on its own?
I'm asking for a simple and good way, because I have complicated and ugly ways to do it. :)
For example, this will make ghci reuse the cabal compiled modules. I came up with this command
line by copying, and modifying the way cabal runs ghc, ensuring that it sets everything the same as the last cabal build, which is necessary to make sure ghci will load the modules.
ghci -package-conf dist/package.conf.inplace -i -idist/build/git-annex/git-annex-tmp -i. -idist/build/autogen -Idist/build/autogen -Idist/build/git-annex/git-annex-tmp -optP-include -optPdist/build/autogen/cabal_macros.h -odir dist/build/git-annex/git-annex-tmp -hidir dist/build/git-annex/git-annex-tmp -stubdir dist/build/git-annex/git-annex-tmp -XHaskell98 dist/build/git-annex/git-annex-tmp/Utility/libdiskfree.o dist/build/git-annex/git-annex-tmp/Utility/libmounts.o
Seems to me it should be possible for a "cabal ghci" to calculate this command line and run it, or perhaps there is a tool I don't know of that already does so.
You can set the odir and ohi options to point to the cabal build directory like so: http://www.haskell.org/ghc/docs/7.6.1/html/users_guide/separate-compilation.html#output-files

How to stop GHC from generating intermediate files?

When compiling a haskell source file via ghc --make foo.hs GHC always leaves behind a variety of intermediate files other than foo.exe. These are foo.hi and foo.o.
I often end up having to delete the .hi and .o files to avoid cluttering up the folders.
Is there a command line option for GHC not to leave behind its intermediate files? (When asked on #haskell, the best answer I got was ghc --make foo.hs && rm foo.hi foo.o.
I've gone through the GHC docs a bit, and there doesn't seem to be a built-in way to remove the temporary files automatically -- after all, GHC needs those intermediate files to build the final executable, and their presence speeds up overall compilation when GHC knows it doesn't have to recompile a module.
However, you might find that setting the -outputdir option will help you out; that will place all of your object files (.o), interface files (.hi), and FFI stub files in the specified directory. It's still "clutter," but at least it's not in your working directory anymore.
GHC now has the options no-keep-hi-files and no-keep-o-files. See here for more information.
My usual workflow is to use cabal rather than ghc directly. This sets the outputdir option into an appropriate build folder and can do things like build haddock documentation for you. All you need is to define the .cabal file for your project and then say cabal install or cabal build instead of run ghc directly. Since you need to follow this process in the end if you ever want to share your work on hackage, it is a good practice to get into and it helps manage package dependencies as well.
You can set the -hidir to /dev/null, I think, sending them there. Also, the -fno-code option in general turns off a lot of output. You might just want to use Cabal.
Turns out that using -hidir/-odir/-outputdir is no good; /dev/null is a file, and not a directory. See http://www.haskell.org/pipermail/xmonad/2010-May/010182.html
2 cents to improve the workflow a bit:
We can put the following alias into the .bashrc (or similar) config
file:
alias hsc='_hsc(){ ghc -no-keep-hi-files -no-keep-o-files "$#";}; _hsc'
And then just call
$ hsc compose.hs
[1 of 1] Compiling Main ( compose.hs, compose.o )
Linking compose ...
$ ls
compose compose.hs

Resources