I've walked through the cabal Distribution.Simple* packages to know that the PreProcessor data type can be used to defined custom pre-processors. But the example provided is not so useful. I don't know how to invoke the pre-processor.
Currently, I just define my own pre-processors in the Setup.hs file.
Are there any complete examples for this feature?
[EDITED]
Check this mail-list archive I just found. But the solution involves transforming from one type of file (identified by the extension of that file) to another.
What I want to do is to inject code into existing .hs files where a custom mark is defined, e.g.
-- <inject point="foo">
-- extra Haskell code goes here
-- </inject>
One of the most important things to do is setting your BuildType in your .Cabal file to Custom. If it stays at Simple Cabal will completely ignore the Setup.hs file.
Build-Type: Custom
Here is an example Custom preprocessor from my package, It first runs cpphs and then runs hsc2hs
#!/usr/bin/env runhaskell
> {-# LANGUAGE BangPatterns #-}
> import Distribution.Simple
> import Distribution.Simple.PreProcess
> import Distribution.Simple.Utils
> import Distribution.PackageDescription
> import Distribution.Simple.LocalBuildInfo
> import Data.Char
> import System.Exit
> import System.IO
> import System.Directory
> import System.FilePath.Windows
> main = let hooks = simpleUserHooks
> xpp = ("xpphs", ppXpp)
> in defaultMainWithHooks hooks { hookedPreProcessors = xpp:knownSuffixHandlers }
>
> ppXpp :: BuildInfo -> LocalBuildInfo -> PreProcessor
> ppXpp build local =
> PreProcessor {
> platformIndependent = True,
> runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity ->
> do info verbosity (inFile++" is being preprocessed to "++outFile)
> let hscFile = replaceExtension inFile "hsc"
> runSimplePreProcessor (ppCpp build local) inFile hscFile verbosity
> handle <- openFile hscFile ReadMode
> source <- sGetContents handle
> hClose handle
> let newsource = unlines $ process $ lines source
> writeFile hscFile newsource
> runSimplePreProcessor (ppHsc2hs build local) hscFile outFile verbosity
> removeFile hscFile
> return ()
> }
This preprocessor will automatically be called by Cabal when any file with the extension .xpphs is found.
In your case just register the preprocessor with a .hs extension. (I'm not sure if Cabal allows this. But if it doesn't you can simply rename the files with the injection point to a .xh or something. This would actually be better since you don't process every file in your project then)
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