I need to communicate some information from compile scripts into Template Haskell. Currently the compile scripts keep the information in the system environment, so I just read it using System.Environment.getEnvironment
wrapped in runIO
. Is there a better way, such as passing some arguments to ghc
(similar to -D...
for the C pre-processor), or perhaps something specifically designed for this purpose in TH?
Since so many people are interested in the question, I'll add my current approach, perhaps somebody will find it useful. Probably the best way would be if TH allowed to read -D
parameters on GHC's command line, but it seems nothing like this is currently implemented.
A simple module allows TH to read compile-time environment. A helper function also allows to read files; for example read the path of a configuration file from the environment and then read the file.
{-# LANGUAGE TemplateHaskell #-} module THEnv ( -- * Compile-time configuration lookupCompileEnv , lookupCompileEnvExp , getCompileEnv , getCompileEnvExp , fileAsString ) where import Control.Monad import qualified Data.Text as T import qualified Data.Text.IO as T import Language.Haskell.TH import Language.Haskell.TH.Syntax (Lift(..)) import System.Environment (getEnvironment) -- Functions that work with compile-time configuration -- | Looks up a compile-time environment variable. lookupCompileEnv :: String -> Q (Maybe String) lookupCompileEnv key = lookup key `liftM` runIO getEnvironment -- | Looks up a compile-time environment variable. The result is a TH -- expression of type @Maybe String@. lookupCompileEnvExp :: String -> Q Exp lookupCompileEnvExp = (`sigE` [t| Maybe String |]) . lift <=< lookupCompileEnv -- We need to explicly type the result so that things like `print Nothing` -- work. -- | Looks up an compile-time environment variable and fail, if it's not -- present. getCompileEnv :: String -> Q String getCompileEnv key = lookupCompileEnv key >>= maybe (fail $ "Environment variable " ++ key ++ " not defined") return -- | Looks up an compile-time environment variable and fail, if it's not -- present. The result is a TH expression of type @String@. getCompileEnvExp :: String -> Q Exp getCompileEnvExp = lift <=< getCompileEnv -- | Loads the content of a file as a string constant expression. -- The given path is relative to the source directory. fileAsString :: FilePath -> Q Exp fileAsString = do -- addDependentFile path -- works only with template-haskell >= 2.7 stringE . T.unpack . T.strip <=< runIO . T.readFile
It can be used like this:
{-# LANGUAGE TemplateHaskell #-} import THEnv main = print $( lookupCompileEnvExp "DEBUG" )
Then:
runhaskell Main.hs
prints Nothing
;DEBUG="yes" runhaskell Main.hs
prints Just "yes"
.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