Differential Documentation with haddock - haskell

If I do a cabal build on my library, then change a file, the next time I run cabal build, I only have to recompile files affected by the changes. I'm not getting the same behavior with the cabal haddock command: when I run it after changing a file, cabal/haddock ends up throwing out all of the previous work and starting from scratch. This is rather time consuming; is there a way to get differential updates to documentation?
Here's a dump of the command cabal issues to generate the documentation.

processModules documentation says:
Create Interfaces and a link environment by typechecking the list of modules using the GHC API and processing the resulting syntax trees.
And that is the core function of haddock. So ATM the answer your question is No.
cabal build doesn't help cabal haddock at all, as haddock type-checks modules with different parameters (e.g. __HADDOCK__ CPP variable enabled)
Making reliable incremental haddock generation is hard, as the code later in the dependency graph can alter the modules documentation previous to that point: particularly the instances listings. Probably one could dump module interfaces.
Looking at the code of processModules the first step is something that could be possible to do incrementally, rest is using global information.
Try turn verbosity to the max i.e. --haddock-options=--verbosity=2 and check how much time is spent between Creating interfaces... and Attaching instances....

Related

How does the workflow with Haskell Stack work?

I don't get the point about Stack.
I used to write my Haskell code in my favourite environment, ran or compiled using GHC(i), and if necessary, installed packages using Cabal. Now, that apparently is not the way to go any more, but I don't understand how to work with Stack. So far, I have only understood that I need to write stack exec ghci instead ghci to start a repl.
Apart from that, the docs always talk about 'projects' for which I have to write some yaml files. But I probably don't have any project -- I just want to launch a GHCi repl and experiment a bit with my ideas. At the moment, this fails with the unability to get the packages that I want to work with installed.
How is working with Stack meant? Is there any explanation of their use cases? Where do I find my use case in there?
Edit. My confusion comes from the fact that I want to work with some software (IHaskell) whose installation guide explains the installation via stack. Assuming I already have a GHCi installed whose package base I maintain e.g. using Cabal. How would I have to set up stack.yaml to make stack use my global GHCi for that project?
First, notice that stack will use its own package base independent from cabal. AFAIK they can't be shared... hence, if you run stack build it'll download packages (including the compiler) on its own package database.
Nevertheless stack allows to use a system compiler (but not other libraries). To do so, in the stack.yaml you must have the following two lines
resolver: lts-XX.XX -- keep reading below
system-ghc: True
The version of the stackage snapshot can be found in: https://www.stackage.org/. Each snapshot works with a different version of the compiler. Be sure to use a snapshot with the same compiler version you have in you system. If it happens your system ghc is greater than any lts, then you can set allow-newer: true in stack.yaml.
Now, if getting a different database from stack feels wrong to you, notice that you can build the project with cabal too, since stack at the end of the day spits out a cabal file. Probably, It wont work out of the box if you build with cabal. You can modify the cabal file to match exactly the version of the packages of the snapshot you are using
In summary:
You can use your system-wide ghc
you can not share libraries installed with cabal.
you can use cabal to build the project, probably modifying the ihaskell.cabal file to match versions of the stackage's snapshot.

Haskell Criterion: Could not load module, hidden package

When I do exactly what this Criterion tutorial says to do to get started, I get an error. What am I doing wrong? Is the tutorial wrong? If so, is there a place that I can learn the right way to use Criterion?
Specifically, as the tutorial says, I ran the following in command line:
cabal update
cabal install -j --disable-tests criterion
This ran without error. Then I copied exactly the example program in the tutorial:
import Criterion.Main
-- The function we're benchmarking.
fib m | m < 0 = error "negative!"
| otherwise = go m
where
go 0 = 0
go 1 = 1
go n = go (n-1) + go (n-2)
-- Our benchmark harness.
main = defaultMain [
bgroup "fib" [ bench "1" $ whnf fib 1
, bench "5" $ whnf fib 5
, bench "9" $ whnf fib 9
, bench "11" $ whnf fib 11
]
]
I put that into a file called benchTest.hs, and then I used the command line to compile the program exactly as it says in the tutorial, but with benchTest in place of Fibber, which is what they called it. Specifically, the I ran the following in the command line:
ghc -O --make benchTest
This resulted in this error:
benchTest.hs:1:1: error:
Could not load module `Criterion.Main'
It is a member of the hidden package `criterion-1.5.13.0'.
You can run `:set -package criterion' to expose it.
(Note: this unloads all the modules in the current scope.)
It is a member of the hidden package `criterion-1.5.13.0'.
You can run `:set -package criterion' to expose it.
(Note: this unloads all the modules in the current scope.)
Use -v (or `:set -v` in ghci) to see a list of the files searched for.
|
1 | import Criterion.Main
| ^^^^^^^^^^^^^^^^^^^^^
Short history of Cabal evolution
Through its history, Cabal has gone through a big transformation of how it
works, which is commonly denoted as v1- commands vs. v2- commands; e.g.
since Cabal 2 you can say cabal v1-install or cabal v2-install. What happens
when you say just cabal install depends on the Cabal version: Cabal 2 will use
v1-install by default while Cabal 3 will use v2-install. The change in
defaults reflects the preferred mode of operation. So much so, v1 has become
basically unmaintained. I don't expect it to be removed soon because there is a
group of hard proponents of the old way. But personally I think that, first, the
new way (fun fact you can use cabal new-install as a synonym) is technically
superior, and second, that newcomers should just use it because it's better
documented and you can have more luck in getting help with it (in many cases,
it's easier to help because of the above-mentioned superiority)
Why v1 was subsumed by v2 (in a nutshell)
The main trouble you can run in with v1 is incompatible dependencies across
several projects. Imagine, you work on project A that depends on package X
of version 42, and, at the same time you're starting with project B that
also depends on X but of version 43. Guess what: you can't v1-build the
two projects on the same machine without wiping out cabal's cache in between.
This was the way it worked in dark ages (from the middle of 2000s to yearly
2010s).
After that, cabal sandboxes arrived. They allowed you to build our imaginary
projects A and B with less hussle but the interface was not great and, more
importantly, every sandbox was independent and, therefore, held a big chunk of
repetitive binaries; e.g. A and B could depend also on Y of the same
version 13, so there's theoretically no need to build and store Y twice,
but that's exactly what cabal sandboxes would do.
Cabal v2 arrived in the late 2010s and brought exactly that: isolation between
projects via an (also recent) GHC feature called environment files and sharing
of build artifacts via Cabal store (so that you don't store many copies of the same thing).
Environments and v2-install
You can create a separate environment for
every project (A, B, etc.) by doing
cabal v2-install --lib X-42 --package-env=.
in the directory of the respective project. Couple notes on the syntax:
v2- can be omitted in Cabal 3 because it's the default;
The order of flags is not important as long as install goes right
after cabal;
--lib is important, because by default you get only executables (that's
what happens with criterion: the package holds an executable);
--package-env=. means: create a GHC environment file in the current
directory (hence .). If the command succeeds you will notice a new
("hidden" on Linux) file in the current directory, named something like
.ghc.environment.x86_64-linux-9.0.2. This is the file that tells all
subsequent calls to GHC in this directory where to search for the libraries compiled by Cabal
and stored in… Cabal store (on Linux it's the ~/.cabal/store directory by
default). In principle, you can use other than . values for environments,
and if the value doesn't correspond to a path, it will be a named
environment. More details in Cabal reference manual… In practice, I find
99.99% cases perfectly served by --package-env=..
X-42 means the package X of version 42 should be added to the newly
created environment. You can omit the version (you will get "some compatible
version"), and you can list more than one package.
What cabal v2-install --lib means if no environment specified
It means the default environment. There is a single shared environment called
default. It has the same very problem that v1 had (see above). So, in
practice it could work but it will be very fragile, especially if you get into
the "project A and project B" situation described above. Even if you only
work with one project now, I suggest using --package-env because it's future
proof.
Why the initial error
As you say, you were using Cabal 2 and therefore v1-install initially and saw
the dreaded "hidden package" error — what's the reason for this? Honestly, I
have no idea. And I doubt it's easy to figure without rolling back to that older
Cabal version and experimenting more. As I say above, v1 is not really maintained
anymore, and even if it looks like a bug in Cabal (which is perfectly possible
especially with earlier releases in the Cabal 2 line), no one will probably
bother about it.
Isn't it sad that old tutorials don't work anymore
It is. Unfortunately, the software technology has to develop to make the world a
better place to live (see the reasons for v2 above again). Sometimes this
development has to break backward compatibility. Ideally, we'd go and update all
educational materials and manuals to reflect the change but that's hardly
possible. Sigh. New users of Haskell has to be careful and creative with respect
to the v1 to v2 shift and try to get a basic understanding of v2 early on
and try to apply it to the good but old tutorials that are still out there.
Are environments the best approach?
Some of the designers and proponents of v2 argue that environment files are a
too subtle of a feature. As a ("proper") alternative, they suggest creating a
full-fledged cabal package for every project you start. This amounts to calling
cabal init, which will create a <project-name>.cabal file in the current
directory, and maintaining the .cabal file, including the list of package
dependencies there; you will also use cabal v2-build to build the project (instead of directly calling GHC).
While more robust, unsurprisingly, this idea doesn't sleep
well with many people who use Haskell to try a lot of small independent things:
it feels lame to create a whole "package" every time. Well, it's just one extra
file in practice, and it's not even extra if you compare it to the
environments-based approach I described above, which also maintains one extra
file, but in that case you don't ever need to edit it by hand (unlike the
.cabal file). All in all, in the scenarios of "trying one small thing" I find
the environments-based approach working better for me. But it does have its
limitations compared to the package-based approach, notably, it's hard to figure out
how to get profiling versions of dependencies in the environment. But that's a
story for another day…
You can find more discussion about how cabal v2-install --lib can be improved in Cabal issue.
If you want to follow the officially blessed way of doing things (i.e. via a package), please, take a minute to read the Getting Started section of the Cabal manual — it's very clear and shows exactly an example of simple application with a dependency on an external package.

Why is "cabal build" so slow compared with "make"?

If I have a package with several executables, which I initially build using cabal build. Now I change one file that impacts just one executable, cabal seems to take about a second or two to examine each executable to see if it's impacted or not. On the other hand, make, given an equivalent number of executables and source files, will determine in a fraction of a second what needs to be recompiled. Why the huge difference? Is there a reason, cabal can't just build its own version of a makefile and go from there?
Disclaimer: I'm not familiar enough with Haskell or make internals to give technical specifics, but some web searching does offer some insight that lines up with my proposal (trying to avoid eliciting opinions by providing references). Also, I'm assuming your makefile is calling ghc, as cabal apparently would.
Proposal: I believe there could be several key reasons, but the main one is that make is written in C, whereas cabal is written in Haskell. This would be coupled with superior dependency checking from make (although I'm not sure how to prove this without looking at the source code). Other supporting reasons, as found on the web:
cabal tries to do a lot more than simply compiling, e.g. appears to take steps with regard to packaging (https://www.haskell.org/cabal/)
cabal is written in haskell, although the run time is written in C (https://en.wikipedia.org/wiki/Glasgow_Haskell_Compiler)
Again, not being overly familiar with make internals, make may simply have a faster dependency checking mechanism, thereby better tracking these changes. I point this out because from the OP it sounds like there is a significant enough difference to where cabal may be doing a blanket check against all dependencies. I suspect this would be the primary reason for the speed difference, if true.
At any rate, these are open source and can be downloaded from their respective sites (haskell.org/cabal/ and savannah.gnu.org/projects/make/) allowing anyone to examine specifics of the implementations.
It is also likely one could see a lot of variance in speed based upon the switches passed to the compilers in use.
HTH at least point you in the right direction.

How to use two different compilers for different targets in a .cabal file?

When I run cabal build it uses some Haskell compiler to build the executables and/or test-suites in my .cabal file.
Can I control which compiler is used for the different targets? Ideally, I would like to have separate build targets that use ghc and ghcjs in the same .cabal file. It seems to me that someone might want to use ghc and hugs or two version of ghc in the same project. Is this currently possible?
Also, how does cabal decide what compiler to use when running cabal build? I saw there is a compiler option in my ~/.cabal/config file but changing it from ghc to ghcjs and uncommenting it, did not seem to change what cabal build does.
The compiler to use is determined during the configure step (or during an install step's implicit configure step, which does not share configuration options with a previous configure step). It is also determined by the entity building the package and cannot be influenced by the person writing the package. Probably what happened to you is that a previous cabal build implicitly invoked the configure step and chose a compiler; future builds will keep a previous choice of compiler over one stuck in your global configuration file. You can countermand that by simply manually running cabal configure again.
It is possible to cause a build to fail with the wrong implementation, e.g.
library
if impl(ghc)
buildable: False
will prevent cabal from trying to build the package using GHC. However, this isn't really useful for building separate parts of a package with separate compilers, as cabal will refuse to install a package unless it can build the whole thing with a single compiler.
Probably the best way forward is to make separate packages for things that should be built by separate compilers.

Profile Haskell without installing profiling libraries for all dependencies

I wish to profile my program written in Haskell.
On compilation, I am told that I do not have profiling libraries for certain dependencies (e.g., criterion) installed and cabal aborts.
I have no interest in profiling parts of those dependencies; code called from main doesn't even use them.
How can I profile my application without installing profiling libraries I don't need and without removing all those dependencies?
A good way to circumvent having to compile everything with profiling is to use cabal sandbox. It allows you to set up a sandbox for one application only, and thereby you won't have to re-install your entire ~/.cabal prefix. You'll need a recent version of Cabal, so run cabal update && cabal install cabal-install first.
Once you initialise a sandbox, create a file cabal.config to include the necessary directives (in your case library-profiling: True; executable-profiling: True may also be handy.)
A side-effect of this is that you can test your code with dependencies that need not be installed globally, for example, experimental versions, or outdated versions.
EDIT: btw, I don't think you need to have profiling enabled for criterion to work. In any case, it works for me without profiling being enabled. Just write a Main module that contains main = defaultMain benchmarks where benchmarks has type [Benchmark], i.e. a list of benchmarks that you've written.
You then compile that file (say, we call it benchmarks.hs with ghc --make -o bench benchmarks.hs, and run the program, ./bench with the appropriate arguments (consult the criterion documentation for details. A good default argument is, say ./bench -o benchmarks.html which will generate a nifty report similar to this one)
I had the same problem this week, and although I had recompiled everything by hand, I was instructed in the IRC channel to do the following:
Go to your cabal config file (in case you don't know where)
Edit the line for enable library profiling (and while you are at it, enable documentation)
Run Cabal Install World
As mentioned in the question you refer to in your comment, a good way to solve this problem in the future is to enable profiling in the cabal configuration. This way all libraries are installed with profiling support. This might not be a satisfying solution but I guess many are opting for it.
If you are only interested in getting an impression of the memory usage of your program you can generate a heap profile of your program using -hT. More precisely, you have to compile the program with -rtsopts to enable RTS options then execute it using +RTS -hT. The compiler generates a file with the extension hp. You can convert the hp file into a postscript file with a heap profile using hp2ps. This should work without any profiling support, but note that I am too lazy to verify it as I have installed all libraries with profiling support ; )

Resources