How to Iterate Over Modules in Cabal Package - haskell

What's the best way to iterate over all the modules (files) in a given package? Concretely, suppose I have
an executable called "runThis"
a cabal package P with files F1.hs, F2.hs, ..., Fn.hs
Whats the easiest way to execute:
runThis F1.hs
runThis F2.hs
...
runThis Fn.hs
?
I thought I might try --with-compiler but that fails with
cabal: The program ghc version >=6.4 is required but the version of runThis
(The other option looks like tweaking the Setup.lhs -- but ideally I'd like to hijack the build process and use "runThis" instead of, say, ghc)
Thanks!

From Duncan Coutts' email:
Question: How to add the preprocessor? I have tried
main =
defaultMainWithHooks
simpleUserHooks{hookedPreProcessors=[("foo",transformation)]}
transformation :: BuildInfo -> LocalBuildInfo -> PreProcessor
That looks right. Here's how to complete it (example taken from the
Cabal haddock docs for the PreProcess module):
transformation _ _ =
PreProcessor {
platformIndependent = True,
runPreProcessor =
mkSimplePreProcessor $ \inFile outFile verbosity -> do
fail $ "transformation: " ++ inFile ++ " " ++ outFile
}
and it works fine:
runghc Setup.hs build
Preprocessing library foo-1.0...
Setup.hs: transformation: Abc.foo dist/build/Abc.hs
But under which circumstances will this function be called? Up to now
I have not succeeded in making cabal call this function.
It calls it when it goes and looks for the module Abc (ie Abc.hs
or .lhs), and since if does not find it, it'll check through the list of
preprocessors and go looking for the corresponding files, ie Abc.foo.

Related

Progress messages not appearing with cabal install for some users

I'm working on a team project using Haskell and whenever I compile our project using 'cabal install' I start seeing the following:
$ cabal clean && cabal install
cleaning...
Resolving dependencies...
Configuring hackathon-0.1...
Building hackathon-0.1...
Preprocessing executable 'hackathon' for hackathon-0.1...
[ 1 of 65] Compiling Data.MaybeUtil ( src/Data/MaybeUtil.hs, dist/dist-sandbox-52369b17/build/hackathon/hackathon-tmp/Data/MaybeUtil.o )
[ 2 of 65] Compiling Data.JQL ( src/Data/JQL.hs, dist/dist-sandbox-52369b17/build/hackathon/hackathon-tmp/Data/JQL.o )
[ 3 of 65] Compiling Data.Tuples ( src/Data/Tuples.hs, dist/dist-sandbox-52369b17/build/hackathon/hackathon-tmp/Data/Tuples.o )
...
$
However, my team members see:
$ cabal clean && cabal install
cleaning...
Resolving dependencies...
Configuring hackathon-0.1...
Building hackathon-0.1...
Installed hackathon-0.1
What is different in their configuration that they don't see all of the "Progress" messages that start with [X of N] My.Module?
I would really like them to be able to see the progress of the compilation as it is happening as our project is quite large and currently has 65 modules and growing. Cheers!
When you run cabal install multithreaded (-j2 and up), single file compilation does not appear on stdout, but should still be written to the log file.
Okay, I decided to just look at the source code and answer my own question. After diving through the cabal-install source code and ending up inside the GHC source I eventually found what I was looking for at the bottom of compiler/main/HscMain.hs:
showModuleIndex :: (Int, Int) -> String
showModuleIndex (i,n) = "[" ++ padded ++ " of " ++ n_str ++ "] "
where
n_str = show n
i_str = show i
padded = replicate (length n_str - length i_str) ' ' ++ i_str
This is the method that prints the Module Index. It is used inside a function called batchMsg which wraps it with a method called compilationProgressMessage:
compilationProgressMsg :: DynFlags -> String -> IO ()
compilationProgressMsg dflags msg
= ifVerbose dflags 1 $
logOutput dflags defaultUserStyle (text msg)
As you can see this method only prints things to the log output filestream if the verbosity is one or higher.
So I have just tried to do this in my terminal:
cabal install -j4 -v1
And then if I tail -f the .cabal-sandbox/logs/package-name.log file then I can see the module indexed compilation messages happening. I think that this solves this problem. Then, when the compilation finishes (or errors out) all of the module messages get printed to stdout. It seems that something is blocking print calls to stdout in parallel compilation in GHC. There is also something that sets the verbosity to 0 when you turn on parallel compilation. I think that both of these are bugs and should be fixed so I may go and try and raise feature requests now.
At any rate I hope that this investigation helps somebody else too. Cheers and thanks for the pointers everybody!

Different behavior of cabal repl for library vs. executable

Using cabal repl seems to do nothing at all when used on library projects, but works fine for executable projects. Is this expected behavior that I just don't understand?
If I have a file containing simply
go = putStrLn "test"
and use cabal init with all the defaults (but choose "library" as the type), then running cabal repl just produces the some text about configuring and preprocessing the library and never enters a REPL environment. The exact same steps, but with "executable" selected as the type, puts me right into GHCi as expected.
The code works fine when loaded directly into GHCi.
For cabal repl to load your modules, you have to first name them in code and then specify them in your project's .cabal file as exposed:
-- MyModule.hs
module MyModule where
go = putStrLn "test"
-- MyProject.cabal
name: MyProject
-- other info ...
library
exposed-modules: MyModule
-- other options ...
Then when you run cabal repl, it'll have access to everything in your sandbox (if present) and the exposed modules. It might also work if you specify them as other-modules instead of exposed-modules, but I haven't tried that one out.

Problems with SourceGraph (Haskell)

I try to visualize an existing Haskell code base with SourceGraph.
SourceGraph mycabal.cabal
But all I get are error messages like this:
Could not parse source file ./src/mysource.hs
SourceGraph: Could not find data file templates/default.html
Any hints what to do or where to look for documentation?
The only documentation I have found so far is this one: http://code.haskell.org/~ivanm/Sample_SourceGraph/SourceGraph/SourceGraph.html which unfortunately only consists of catchy images but with no hints how to produce them.
Regarding your immediate question, it seems like the best documentation here is the source: http://code.haskell.org/SourceGraph/
I tried it on a repository of my own, and ran into the parsing issue, too. This is haskell-src-exts failing to parse a module. The following patch shows the actual error:
--- Parsing.hs 2013-02-14 12:59:34.000000000 +0100
+++ ../SourceGraph-0.7.0.5-fixed/Parsing.hs 2014-04-08 20:49:54.000000000 +0200
## -64,7 +64,7 ##
parseFile :: FileContents -> Either FilePath Module
parseFile (p,f) = case (parseFileContentsWithMode mode f) of
(ParseOk hs) -> Right hs
- _ -> Left p
+ x -> Left $ p ++ ": " ++ show x
where
mode = defaultParseMode { parseFilename = p
, fixities = Nothing
It turns out that most of my failing modules failed because "MultiParamTypeClasses is not enabled". This is apparently haskell-src-exts being rightfully strict, while ghc is happy without the MultiParamTypeClasses extension: https://github.com/haskell-suite/haskell-src-exts/issues/29
So as a quick fix, try adding
{-# LANGUAGE MultiParamTypeClasses #-}
at the top of your failing modules.
Just ran into a similar issue, so I thought I'd document here what I did. I put my changes in a patch file.
https://gist.github.com/ivanperez-keera/b398ce71a22e8a4849f3
cabal sandbox init
cabal unpack SourceGraph
wget https://gist.githubusercontent.com/ivanperez-keera/b398ce71a22e8a4849f3/raw/bf26ffc45564934c0f175e7619ded8a299a9b7d5/verbose-sourcegraph.patch
cd SourceGraph-0.7.0.6/
patch -i ../verbose-sourcegraph.patch
cd ..
cabal install SourceGraph-0.7.0.6/
Most of the "errors" in my files where due to bang patterns and multi param type classes. There must be a better solution to make SourceGraph's parse mode default to the same as GHC.

How to pass command-line options to Alex in Cabal

In my current project I have a file Tokens.x that needs to be compiled to Tokens.hs by Alex. In my .cabal file I have listed Tokens in the other-modules section and cabal build happily creates the file.
However it does so without the -g option that instructs Alex to create a GHC optimized version of the file. This option represents a 10x speed up in scanning when used with GHC and is also an order of magnitude faster to compile.
How do I tell cabal to included the -g option when compiling using GHC?
AFAIK, with Cabal you can currently only specify program options in the configuration file or via the command line, but not in a .cabal file.
There's an open issue about this: https://github.com/haskell/cabal/issues/1223
However, looking at the sources for Cabal, I find that your particular problem seems to be solved by default. In Distribution.Simple.PreProcess, there's:
ppAlex :: BuildInfo -> LocalBuildInfo -> PreProcessor
ppAlex _ lbi = pp { platformIndependent = True }
where pp = standardPP lbi alexProgram (hcFlags hc)
hc = compilerFlavor (compiler lbi)
hcFlags GHC = ["-g"]
hcFlags _ = []
This means that if Cabal is used with GHC, then -g is automatically passed to Alex when it's being used as a preprocessor.

C compiler selection in cabal package

I decided to add some flags to control the way that C source file is compiled (i.e. something like use-clang, use-intel etc.).
C-Sources: c_lib/tiger.c
Include-Dirs: c_lib
Install-Includes: tiger.h
if flag(debug)
GHC-Options: -debug -Wall -fno-warn-orphans
CPP-Options: -DDEBUG
CC-Options: -DDEBUG -g
else
GHC-Options: -Wall -fno-warn-orphans
Question is: which options in descritpion file need to be modified to change C compiler? I did found only CC-Options.
There is no straightforward way, but it is possible.
Assuming that you are using Distribution.Simple, you basically need to add a user hook to the build stage.
All of the following changes need to appear in Setup.hs:
Change main to use a build hook, something like:
main :: IO ()
main = defaultMainWithHooks simpleUserHooks { buildHook = myBuildHook }
Next you need a build hook. It will likely look something like the following:
myBuildHook pkg_descr local_bld_info user_hooks bld_flags =
do
let lib = fromJust (library pkg_descr)
lib_bi = libBuildInfo lib
custom_bi = customFieldsBI lib_bi
cpp_name = fromJust (lookup "x-cc-name" custom_bi)
c_srcs = cSources lib_bi
cc_opts = ccOptions lib_bi
inc_dirs = includeDirs lib_bi
lib_dirs = extraLibDirs lib_bi
bld_dir = buildDir local_bld_info
-- Compile C/C++ sources
putStrLn "invoking my compile phase"
objs <- mapM (compileCxx cpp_name cc_opts inc_dirs bld_dir) c_srcs
-- Remove C/C++ source code from the hooked build (don't change libs)
let lib_bi' = lib_bi { cSources = [] }
lib' = lib { libBuildInfo = lib_bi' }
pkg_descr' = pkg_descr { library = Just lib' }
-- The following line invokes the standard build behaviour
putStrLn "Invoke default build hook"
bh <- buildHook simpleUserHooks pkg_descr' local_bld_info user_hooks bld_flags
return bh
The code above probably needs unpacking a bit. The let clauses are basically about unpacking the required data fields from the structures passed to the build hook. Notice that you can create custom stanzas in your foo.cabal. I have provided the code to support a stanza something like:
x-cc-name: icc
As a means to specify your compiler. Having extracted all of the source files, you map over them using a function to compile a single file (NB: this is sub-optimal in some cases, e.g. those compilers which can efficiently compile multiple source files to produce a single object output and benefit from large scale optimizations, but we'll leave that aside for now).
Last of all, as we've now compiled the C/C++ code, remove it from the build structures before you pass everything on to the default build hook.
Sorry that this is more of a 'HOWTO' than a canned answer, but it should help you to get going.
I should mention that the code is untested. I have adapted it from some work I have been doing on the wxHaskell build system, so I know the idea works fine. The Cabal API is actually pretty well documented - it suffers mainly from being somewhat unstable around some of these areas.
There really doesn't seem to be any way to specify this in a .cabal file; the only thing we seem to have at the moment that would be even remotely useful here is --with-<prog>=path.
I suggest you try filing a ticket against Cabal on the trac.
4.10.1. Replacing the program for one or more phases
-pgmc cmd
        Use cmd as the C compiler.
This works for ghc --make, but I'm not sure how to get Cabal to apply this to the C file compilation.

Resources