Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding cabal packages when using the GHC API

I'm trying to make a program that typechecks haskell files for me using the GHC API. I've gotten the type checking to work for local files, but I have a specific cabal package that I need to be have available as well (the same package this executable will be a part of). How do add this import dependency?

I also tried compiling with ghc command line to figure this out, using ghc -package PKG-VER --make Test.hs -v but it only seems to look in the local directory for imports.

My current code looks like this:

import           Control.Exception
import           Control.Monad
import           Control.Monad.State
import           DynFlags
import           Exception
import           GHC
import           GHC.Paths           (libdir)
typecheck :: MonadIO m => [FilePath] -> FilePath -> m ()
typecheck otherincludes fp =
  liftIO . defaultErrorHandler defaultLogAction . runGhc (Just libdir) $ do
    dynflags <- getSessionDynFlags
    void $ setSessionDynFlags dynflags { includePaths = otherIncludes ++ includePaths dynflags }
    target <- guessTarget fp Nothing
    setTargets [target]
    void $ load LoadAllTargets
    deps <- depanal [] False
    forM_ deps $ \ms -> parseModule ms >>= typecheckModule
like image 992
Adam Bergmark Avatar asked Sep 03 '12 10:09

Adam Bergmark


1 Answers

I managed to make your code read and typecheck itself as followS:

package Test where
import           Control.Exception
import           Control.Monad
import           Control.Monad.State
import           DynFlags
import           Exception
import           GHC
import           GHC.Paths           (libdir)
typecheck :: MonadIO m => [FilePath] -> FilePath -> m ()
typecheck otherincludes fp =
  liftIO . defaultErrorHandler defaultLogAction . runGhc (Just libdir) $ do
    dynflags <- getSessionDynFlags
    void $ setSessionDynFlags dynflags {
        includePaths = otherincludes ++ includePaths dynflags,
        packageFlags = [ExposePackage "ghc"]} }
    target <- guessTarget fp Nothing
    setTargets [target]
    void $ load LoadAllTargets
    deps <- depanal [] False
    forM_ deps $ \ms -> parseModule ms >>= typecheckModule

here is how it runs in ghci:

$ ghci Test.hs -package ghc
GHCi, version 7.4.1: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Loading package array-0.4.0.0 ... linking ... done.
Loading package deepseq-1.3.0.0 ... linking ... done.
Loading package containers-0.4.2.1 ... linking ... done.
Loading package filepath-1.3.0.0 ... linking ... done.
Loading package old-locale-1.0.0.4 ... linking ... done.
Loading package old-time-1.1.0.0 ... linking ... done.
Loading package bytestring-0.9.2.1 ... linking ... done.
Loading package unix-2.5.1.0 ... linking ... done.
Loading package directory-1.1.0.2 ... linking ... done.
Loading package pretty-1.1.1.0 ... linking ... done.
Loading package process-1.1.0.1 ... linking ... done.
Loading package Cabal-1.14.0 ... linking ... done.
Loading package binary-0.5.1.0 ... linking ... done.
Loading package bin-package-db-0.0.0.0 ... linking ... done.
Loading package hoopl-3.8.7.3 ... linking ... done.
Loading package hpc-0.5.1.1 ... linking ... done.
Loading package template-haskell ... linking ... done.
Loading package ghc-7.4.1 ... linking ... done.
Ok, modules loaded: Test.
Prelude Test> typecheck [] "Test.hs"
Loading package transformers-0.3.0.0 ... linking ... done.
Loading package mtl-2.1.1 ... linking ... done.
Prelude Test> 

So the trick seems to be to pass the exposed packages in the dynflags argument to setSessionDynFlags. See the DynFlags module for some documentation.

like image 96
Joachim Breitner Avatar answered Sep 29 '22 18:09

Joachim Breitner