fficxx-0.2.1: lib/FFICXX/Generate/Builder.hs
{-# LANGUAGE ScopedTypeVariables #-}
-----------------------------------------------------------------------------
-- |
-- Module : FFICXX.Generate.Builder
-- Copyright : (c) 2011-2013,2015 Ian-Woo Kim
--
-- License : BSD3
-- Maintainer : Ian-Woo Kim <ianwookim@gmail.com>
-- Stability : experimental
-- Portability : GHC
--
-----------------------------------------------------------------------------
module FFICXX.Generate.Builder where
import Data.Char (toUpper)
import qualified Data.HashMap.Strict as HM
import Data.List (intercalate)
import Data.Monoid (mempty)
import System.FilePath ((</>), (<.>))
import System.Directory (getCurrentDirectory)
import System.Process (readProcess)
import Text.StringTemplate hiding (render)
--
import FFICXX.Generate.Code.Cabal
import FFICXX.Generate.Code.Cpp
import FFICXX.Generate.Code.Dependency
import FFICXX.Generate.Config
import FFICXX.Generate.Code.Cpp
import FFICXX.Generate.Code.Dependency
import FFICXX.Generate.Config
import FFICXX.Generate.Generator.ContentMaker
import FFICXX.Generate.Generator.Driver
import FFICXX.Generate.Type.Annotate
import FFICXX.Generate.Type.Class ( Cabal(..)
, CabalAttr(..)
, Class
, ClassModule
, Namespace(NS)
, TopLevelFunction
, TopLevelImportHeader
)
import FFICXX.Generate.Type.PackageInterface
import FFICXX.Generate.Util
--
import qualified FFICXX.Paths_fficxx as F
-- |
cabalTemplate :: String
cabalTemplate = "Pkg.cabal"
-- |
mkCabalFile :: FFICXXConfig
-> STGroup String
-> (Cabal, CabalAttr)
-> String
-> (TopLevelImportHeader,[ClassModule])
-> [String] -- ^ extra libs
-> FilePath
-> IO ()
mkCabalFile config
templates
(cabal, cabalattr)
summarymodule
(tih,classmodules)
extralibs
cabalfile
= do
cpath <- getCurrentDirectory
let str = renderTemplateGroup
templates
( [ ("licenseField", "license: " ++ license)
| Just license <- [cabalattr_license cabalattr] ] ++
[ ("licenseFileField", "license-file: " ++ licensefile)
| Just licensefile <- [cabalattr_licensefile cabalattr] ] ++
[ ("pkgname", cabal_pkgname cabal)
, ("version", "0.0")
, ("buildtype", "Simple")
, ("deps", "")
, ("csrcFiles", genCsrcFiles (tih,classmodules))
, ("includeFiles", genIncludeFiles (cabal_pkgname cabal) classmodules)
, ("cppFiles", genCppFiles (tih,classmodules))
, ("exposedModules", genExposedModules summarymodule classmodules)
, ("otherModules", genOtherModules classmodules)
, ("extralibdirs", intercalate ", " $ cabalattr_extralibdirs cabalattr)
, ("extraincludedirs", intercalate ", " $ cabalattr_extraincludedirs cabalattr)
, ("extraLibraries", concatMap (", " ++) extralibs)
, ("cabalIndentation", cabalIndentation)
]
)
cabalTemplate
writeFile cabalfile str
macrofy :: String -> String
macrofy = map ((\x->if x=='-' then '_' else x) . toUpper)
simpleBuilder :: String -> [(String,([Namespace],[HeaderName]))]
-> (Cabal, CabalAttr, [Class], [TopLevelFunction])
-> [String] -- ^ extra libs
-> IO ()
simpleBuilder summarymodule m (cabal, cabalattr, myclasses, toplevelfunctions) extralibs = do
let pkgname = cabal_pkgname cabal
putStrLn ("generating " ++ pkgname)
cwd <- getCurrentDirectory
let cfg = FFICXXConfig { fficxxconfig_scriptBaseDir = cwd
, fficxxconfig_workingDir = cwd </> "working"
, fficxxconfig_installBaseDir = cwd </> pkgname
}
workingDir = fficxxconfig_workingDir cfg
installDir = fficxxconfig_installBaseDir cfg
(mods,cihs,tih) = mkAll_ClassModules_CIH_TIH
(pkgname, mkClassNSHeaderFromMap (HM.fromList m))
(myclasses, toplevelfunctions)
hsbootlst = mkHSBOOTCandidateList mods
cglobal = mkGlobal myclasses
-- summarymodule = -- pkgname -- "Snappy"
cabalFileName = pkgname <.> "cabal" -- "Snappy.cabal"
templateDir <- F.getDataDir >>= return . (</> "template")
(templates :: STGroup String) <- directoryGroup templateDir
--
notExistThenCreate workingDir
notExistThenCreate installDir
notExistThenCreate (installDir </> "src")
notExistThenCreate (installDir </> "csrc")
--
putStrLn "cabal file generation"
mkCabalFile cfg templates (cabal, cabalattr) summarymodule (tih,mods) extralibs (workingDir </> cabalFileName)
--
putStrLn "header file generation"
let typmacro = TypMcro ("__" ++ macrofy (cabal_pkgname cabal) ++ "__") {- "__SNAPPY__" -}
writeTypeDeclHeaders templates workingDir typmacro pkgname cihs
mapM_ (writeDeclHeaders templates workingDir typmacro pkgname) cihs
writeTopLevelFunctionHeaders templates workingDir typmacro pkgname tih
--
putStrLn "cpp file generation"
mapM_ (writeCppDef templates workingDir) cihs
writeTopLevelFunctionCppDef templates workingDir typmacro pkgname tih
--
putStrLn "RawType.hs file generation"
mapM_ (writeRawTypeHs templates workingDir) mods
--
putStrLn "FFI.hsc file generation"
mapM_ (writeFFIHsc templates workingDir) mods
--
putStrLn "Interface.hs file generation"
mapM_ (writeInterfaceHs mempty templates workingDir) mods
--
putStrLn "Cast.hs file generation"
mapM_ (writeCastHs templates workingDir) mods
--
putStrLn "Implementation.hs file generation"
mapM_ (writeImplementationHs mempty templates workingDir) mods
--
putStrLn "hs-boot file generation"
mapM_ (writeInterfaceHSBOOT templates workingDir) hsbootlst
--
putStrLn "module file generation"
mapM_ (writeModuleHs templates workingDir) mods
--
putStrLn "summary module generation generation"
writePkgHs summarymodule templates workingDir mods tih
--
putStrLn "copying"
touch (workingDir </> "LICENSE")
copyFileWithMD5Check (workingDir </> cabalFileName) (installDir </> cabalFileName)
copyFileWithMD5Check (workingDir </> "LICENSE") (installDir </> "LICENSE")
-- copyPredefined templateDir (srcDir ibase) pkgname
copyCppFiles workingDir (csrcDir installDir) pkgname (tih,cihs)
mapM_ (copyModule workingDir (srcDir installDir) summarymodule) mods
-- | some dirty hack. later, we will do it with more proper approcah.
touch :: FilePath -> IO ()
touch fp = do
readProcess "touch" [fp] ""
return ()