I've got the start of a haskell application and I want to see how the build tools behave. One of the things I would like to see is the Haskell coverage reports, through hpc (Haskell Program Coverage -> I didn't find this tag on so, hpc points to high perf computing, on a side note).
The structure of my application is
Main
src/
ModuleA
ModuleB
tests/
ModuleBTest
I have unit tests for moduleB, and I run those unit-tests through cabal test. Before, I configure cabal to spit out the hpc data through
cabal configure --ghc-options=-fhpc --enable-tests
I then build and test,
cabal build
cabal test unit-tests (that's the name of the test suite in the cabal file)
and I indeed see a report and all seems well. However, moduleA is not referred from within moduleB, it's only referred from the Main. I don't have tests (yet) for the Main module.
The thing is, I expected to see moduleA pop up in the hpc output, highlighted completely in yellow and really waving at me that there are no tests for this module, but that doesn't seem to be the case. I noticed that the .mix files are created for this 'unused' module, so I suspect the build step went ok but it goes wrong in the cabal test step.
If I go through ghci and I compile the unit tests while explicitly moduleA on the list of modules to compile then I do get hpc to show me that this module has no tests at all. So I suspect cabal optimizes this moduleA away (as it's 'unused') somewhere, but I don't really see how or where.
Now, I do realize that this might not be a real life situation, as moduleA is only referenced from within the main method, moduleB doesn't reference moduleA and I don't test the Main module (yet), but still I would have felt a lot better if it would at least show up in the program coverage as a hole in my tests the size of a battleship. Anybody an idea?
Note : I realize that my question might boil down to : "How do I tell cabal not to optimize unused modules away?" but I wanted to present the complete problem.
Kasper
First, make sure all of your modules are listed in the other-modules
cabal field.
Even though in my experience sometimes applications seem to work their way around without specifying everything there - it can often cause mysterious linking issues, and I assume it could cause situations like yours.
Now, other than that, I don't think cabal would optimize your modules like that, but GHC's dead code elimination. So if your code is not used at all (just one actual usage per module has to exist), GHC wouldn't even care for it.
Unfortunately I haven't seen a flag to change that. You may want to make a meaningless usage for every module in your tests project, just to get things visible.
2.1 Dead code elimination
Does GHC remove code that you're not actually using?
Yes and no. If there is something in a module that isn't exported and isn't used by anything that is exported, it gets ignored. (This makes your compiled program smaller.) So at the module level, yes, GHC does dead code elimination.
On the other hand, if you import a module and use just 1 function from it, all of the code for all of the functions in that module get linked in. So in this sense, no, GHC doesn't do dead code elimination.
(There is a switch to make GHC spit out a separate object file for each individual function in a module. If you use this, only the functions are actually used will get linked into your executable. But this tends to freak out the linker program...)
If you want to be warned about unused code (Why do you have it there if it's unused? Did you forget to type something?) you can use the -fwarn-unused-binds option (or just -Wall).
- GHC optimisations - HaskellWiki
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With