Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build and use a bootstrap executable in a Cabal package

Tags:

haskell

cabal

I would like to Cabalize a Haskell project in order to upload it to Hackage. It consists of one standard .hs file which builds a bootstrap executable, and eight nonstandard .lhs files which are processed by the bootstrap executable to yield the .hs files which build the production executable.

In other words, my project is a custom literate preprocessor (with HTML markup, code grooming, here documents) which is written in itself. It depends on a bootstrap version which can translate the literate code for the production version, but which is not suitable for general use. So I do not want the bootstrap version to be a separate package; it is meant to be used only once, here.

I have been using a Makefile, which is possible in Cabal but not in the spirit of Cabal. What is a clean way to do this, that takes maximal advantage of the generality of Cabal? I have not seen any suggestions for this in the online documentation, short of either rewriting Distribution.Simple or using a Makefile.

like image 950
Syzygies Avatar asked Sep 24 '12 19:09

Syzygies


1 Answers

I think that releasing your bootstrap executable as a separate package is the easiest solution, and there are instructions available on how to integrate your custom preprocessor with Cabal.

If you don't want to do that, try making your preprocessor part of Setup.hs (don't forget to set the build type to Custom!). You can run your preprocessor during the configure step. Look at how wxcore does this.

Here's a working example (patterned after wxcore):

Setup.hs:

import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup
import Distribution.PackageDescription

import Control.Monad (forM_)
import System.Directory (copyFile)
import System.FilePath (replaceExtension)

main :: IO ()
main = defaultMainWithHooks simpleUserHooks { confHook = myConfHook }

-- Replace 'copyFile' with more complicated logic.
runMyPreprocessor :: FilePath -> IO ()
runMyPreprocessor abcFile = copyFile abcFile (replaceExtension abcFile ".hs")

myConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags
              -> IO LocalBuildInfo
myConfHook (pkgDesc, hbi) flags = do
  let extraSrc = extraSrcFiles . packageDescription $ pkgDesc
  forM_ extraSrc runMyPreprocessor

  confHook simpleUserHooks (pkgDesc, hbi) flags

my-preprocessor.cabal:

name:                my-preprocessor
version:             0.1.0.0
build-type:          Custom
cabal-version:       >=1.8
extra-source-files:  Main.abc

executable my-preprocessor
  main-is: Main.hs
  build-depends:       base < 5

Main.abc:

module Main
       where

main :: IO ()
main = putStrLn "Hello"
like image 152
Mikhail Glushenkov Avatar answered Oct 22 '22 04:10

Mikhail Glushenkov