Skip to content

Commit

Permalink
Merge pull request #112 from wavewave/dev/111/json
Browse files Browse the repository at this point in the history
JSON file creation for generated cabal information
wavewave authored Sep 9, 2018
2 parents 020dfb6 + 665fb94 commit 73ffd58
Showing 7 changed files with 336 additions and 169 deletions.
44 changes: 23 additions & 21 deletions fficxx/fficxx.cabal
Original file line number Diff line number Diff line change
@@ -16,27 +16,29 @@ Source-repository head

Library
hs-source-dirs: lib
Build-Depends: base == 4.*,
Cabal,
bytestring,
containers,
data-default,
directory,
either,
errors,
filepath>1,
hashable,
haskell-src-exts >= 1.18,
lens > 3,
mtl>2,
process,
pureMD5,
split,
transformers >= 0.3,
template,
template-haskell,
text,
unordered-containers
Build-Depends: base == 4.*
, aeson
, aeson-pretty
, bytestring
, Cabal
, containers
, data-default
, directory
, either
, errors
, filepath>1
, hashable
, haskell-src-exts >= 1.18
, lens > 3
, mtl>2
, process
, pureMD5
, split
, transformers >= 0.3
, template
, template-haskell
, text
, unordered-containers


Exposed-Modules:
141 changes: 87 additions & 54 deletions fficxx/lib/FFICXX/Generate/Builder.hs
Original file line number Diff line number Diff line change
@@ -15,24 +15,26 @@

module FFICXX.Generate.Builder where

import Control.Monad ( forM_, void, when )
import Control.Monad (void,when)
import qualified Data.ByteString.Lazy.Char8 as L
import Data.Char ( toUpper )
import Data.Digest.Pure.MD5 ( md5 )
import Data.Monoid ( (<>), mempty )
import Language.Haskell.Exts.Pretty ( prettyPrint )
import System.FilePath ( (</>), (<.>), splitExtension )
import System.Directory ( copyFile, doesDirectoryExist
, doesFileExist, getCurrentDirectory )
import System.IO ( hPutStrLn, withFile, IOMode(..) )
import System.Process ( readProcess, system )
import Data.Char (toUpper)
import Data.Digest.Pure.MD5 (md5)
import Data.Foldable (for_)
import Data.Monoid ((<>),mempty)
import Language.Haskell.Exts.Pretty (prettyPrint)
import System.FilePath ((</>),(<.>),splitExtension)
import System.Directory (copyFile, doesDirectoryExist
,doesFileExist,getCurrentDirectory)
import System.IO (hPutStrLn,withFile,IOMode(..))
import System.Process (readProcess,system )
--
import FFICXX.Generate.Code.Cabal
import FFICXX.Generate.Dependency
import FFICXX.Generate.Config
import FFICXX.Generate.ContentMaker
import FFICXX.Generate.Type.Cabal (Cabal(..),AddCInc(..),AddCSrc(..),CabalName(..))
import FFICXX.Generate.Type.Config (ModuleUnitMap(..))
import FFICXX.Generate.Type.Cabal (Cabal(..),CabalName(..)
,AddCInc(..),AddCSrc(..))
import FFICXX.Generate.Type.Config (ModuleUnitMap(..))
import FFICXX.Generate.Type.Class
import FFICXX.Generate.Type.Module
import FFICXX.Generate.Type.PackageInterface
@@ -49,8 +51,12 @@ simpleBuilder :: String
-> [(String,[String])] -- ^ extra module
-> IO ()
simpleBuilder topLevelMod mumap (cabal,classes,toplevelfunctions,templates) extralibs extramods = do
putStrLn "----------------------------------------------------"
putStrLn "-- fficxx code generation for Haskell-C++ binding --"
putStrLn "----------------------------------------------------"

let pkgname = cabal_pkgname cabal
putStrLn ("generating " <> unCabalName pkgname)
putStrLn ("Generating " <> unCabalName pkgname)
cwd <- getCurrentDirectory
let cfg = FFICXXConfig { fficxxconfig_scriptBaseDir = cwd
, fficxxconfig_workingDir = cwd </> "working"
@@ -67,86 +73,113 @@ simpleBuilder topLevelMod mumap (cabal,classes,toplevelfunctions,templates) extr
(cabal_additional_c_srcs cabal)
hsbootlst = mkHSBOOTCandidateList mods
cabalFileName = unCabalName pkgname <.> "cabal"
jsonFileName = unCabalName pkgname <.> "json"
--
notExistThenCreate workingDir
notExistThenCreate installDir
notExistThenCreate (installDir </> "src")
notExistThenCreate (installDir </> "csrc")
--
putStrLn "cabal file generation"
putStrLn "Generating Cabal file"
buildCabalFile cabal topLevelMod pkgconfig extralibs (workingDir</>cabalFileName)
--
putStrLn "header file generation"
putStrLn "Generating JSON file"
buildJSONFile cabal topLevelMod pkgconfig extralibs (workingDir</>jsonFileName)
--
putStrLn "Generating Header file"
let typmacro = TypMcro ("__" <> macrofy (unCabalName (cabal_pkgname cabal)) <> "__")
gen :: FilePath -> String -> IO ()
gen file str =
let path = workingDir </> file in withFile path WriteMode (flip hPutStrLn str)


gen (unCabalName pkgname <> "Type.h") (buildTypeDeclHeader typmacro (map cihClass cihs))
mapM_ (\hdr -> gen (unHdrName (cihSelfHeader hdr)) (buildDeclHeader typmacro (unCabalName pkgname) hdr)) cihs
gen (tihHeaderFileName tih <.> "h") (buildTopLevelHeader typmacro (unCabalName pkgname) tih)
forM_ tcms $ \m ->
for_ cihs $ \hdr -> gen
(unHdrName (cihSelfHeader hdr))
(buildDeclHeader typmacro (unCabalName pkgname) hdr)
gen
(tihHeaderFileName tih <.> "h")
(buildTopLevelHeader typmacro (unCabalName pkgname) tih)
for_ tcms $ \m ->
let tcihs = tcmTCIH m
in forM_ tcihs $ \tcih ->
in for_ tcihs $ \tcih ->
let t = tcihTClass tcih
hdr = unHdrName (tcihSelfHeader tcih)
in gen hdr (buildTemplateHeader typmacro t)
--
putStrLn "cpp file generation"
mapM_ (\hdr -> gen (cihSelfCpp hdr) (buildDefMain hdr)) cihs
putStrLn "Generating Cpp file"
for_ cihs (\hdr -> gen (cihSelfCpp hdr) (buildDefMain hdr))
gen (tihHeaderFileName tih <.> "cpp") (buildTopLevelCppDef tih)
--
putStrLn "additional header/source generation"
mapM_ (\(AddCInc hdr txt) -> gen hdr txt) (cabal_additional_c_incs cabal)
mapM_ (\(AddCSrc hdr txt) -> gen hdr txt) (cabal_additional_c_srcs cabal)
putStrLn "Generating Additional Header/Source"
for_ (cabal_additional_c_incs cabal) (\(AddCInc hdr txt) -> gen hdr txt)
for_ (cabal_additional_c_srcs cabal) (\(AddCSrc hdr txt) -> gen hdr txt)
--
putStrLn "RawType.hs file generation"
mapM_ (\m -> gen (cmModule m <.> "RawType" <.> "hs") (prettyPrint (buildRawTypeHs m))) mods
putStrLn "Generating RawType.hs"
for_ mods $ \m -> gen
(cmModule m <.> "RawType" <.> "hs")
(prettyPrint (buildRawTypeHs m))
--
putStrLn "FFI.hsc file generation"
mapM_ (\m -> gen (cmModule m <.> "FFI" <.> "hsc") (prettyPrint (buildFFIHsc m))) mods
putStrLn "Generating FFI.hsc"
for_ mods $ \m -> gen
(cmModule m <.> "FFI" <.> "hsc")
(prettyPrint (buildFFIHsc m))
--
putStrLn "Interface.hs file generation"
mapM_ (\m -> gen (cmModule m <.> "Interface" <.> "hs") (prettyPrint (buildInterfaceHs mempty m))) mods
putStrLn "Generating Interface.hs"
for_ mods $ \m -> gen
(cmModule m <.> "Interface" <.> "hs")
(prettyPrint (buildInterfaceHs mempty m))
--
putStrLn "Cast.hs file generation"
mapM_ (\m -> gen (cmModule m <.> "Cast" <.> "hs") (prettyPrint (buildCastHs m))) mods
putStrLn "Generating Cast.hs"
for_ mods $ \m -> gen
(cmModule m <.> "Cast" <.> "hs")
(prettyPrint (buildCastHs m))
--
putStrLn "Implementation.hs file generation"
mapM_ (\m -> gen (cmModule m <.> "Implementation" <.> "hs") (prettyPrint (buildImplementationHs mempty m))) mods
putStrLn "Generating Implementation.hs"
for_ mods $ \m -> gen
(cmModule m <.> "Implementation" <.> "hs")
(prettyPrint (buildImplementationHs mempty m))
--
putStrLn "Template.hs file generation"
mapM_ (\m -> gen (tcmModule m <.> "Template" <.> "hs") (prettyPrint (buildTemplateHs m))) tcms
putStrLn "Generating Template.hs"
for_ tcms $ \m -> gen
(tcmModule m <.> "Template" <.> "hs")
(prettyPrint (buildTemplateHs m))
--
putStrLn "TH.hs file generation"
mapM_ (\m -> gen (tcmModule m <.> "TH" <.> "hs") (prettyPrint (buildTHHs m))) tcms

putStrLn "Generating TH.hs"
for_ tcms $ \m -> gen
(tcmModule m <.> "TH" <.> "hs")
(prettyPrint (buildTHHs m))

--
-- TODO: Template.hs-boot need to be generated as well
putStrLn "hs-boot file generation"
mapM_ (\m -> gen (m <.> "Interface" <.> "hs-boot") (prettyPrint (buildInterfaceHSBOOT m))) hsbootlst
putStrLn "Generating hs-boot file"
for_ hsbootlst $ \m -> gen
(m <.> "Interface" <.> "hs-boot")
(prettyPrint (buildInterfaceHSBOOT m))
--



putStrLn "module file generation"
mapM_ (\m -> gen (cmModule m <.> "hs") (prettyPrint (buildModuleHs m))) mods
putStrLn "Genering Module summary file"
for_ mods $ \m -> gen
(cmModule m <.> "hs")
(prettyPrint (buildModuleHs m))
--
putStrLn "top level module generation generation"
putStrLn "Generating Top-level Module"
gen (topLevelMod <.> "hs") (prettyPrint (buildTopLevelHs topLevelMod (mods,tcms) tih))
--
putStrLn "copying"
putStrLn "Copying generated files to target directory"
touch (workingDir </> "LICENSE")
copyFileWithMD5Check (workingDir </> cabalFileName) (installDir </> cabalFileName)
copyFileWithMD5Check (workingDir </> jsonFileName) (installDir </> jsonFileName)
copyFileWithMD5Check (workingDir </> "LICENSE") (installDir </> "LICENSE")

copyCppFiles workingDir (csrcDir installDir) (unCabalName pkgname) pkgconfig
mapM_ (copyModule workingDir (srcDir installDir)) mods
mapM_ (copyTemplateModule workingDir (srcDir installDir)) tcms
for_ mods (copyModule workingDir (srcDir installDir))
for_ tcms (copyTemplateModule workingDir (srcDir installDir))
moduleFileCopy workingDir (srcDir installDir) $ topLevelMod <.> "hs"

putStrLn "----------------------------------------------------"
putStrLn "-- Code generation has been completed. Enjoy! --"
putStrLn "----------------------------------------------------"


-- | some dirty hack. later, we will do it with more proper approcah.

@@ -181,20 +214,20 @@ copyCppFiles wdir ddir cprefix (PkgConfig _ cihs tih _ tcihs acincs acsrcs) = do
>>= flip when (copyFileWithMD5Check (wdir </> tlhfile) (ddir </> tlhfile))
doesFileExist (wdir </> tlcppfile)
>>= flip when (copyFileWithMD5Check (wdir </> tlcppfile) (ddir </> tlcppfile))
forM_ cihs $ \header-> do
for_ cihs $ \header-> do
let hfile = unHdrName (cihSelfHeader header)
cppfile = cihSelfCpp header
copyFileWithMD5Check (wdir </> hfile) (ddir </> hfile)
copyFileWithMD5Check (wdir </> cppfile) (ddir </> cppfile)

forM_ tcihs $ \header-> do
for_ tcihs $ \header-> do
let hfile = unHdrName (tcihSelfHeader header)
copyFileWithMD5Check (wdir </> hfile) (ddir </> hfile)

forM_ acincs $ \(AddCInc header _) ->
for_ acincs $ \(AddCInc header _) ->
copyFileWithMD5Check (wdir </> header) (ddir </> header)

forM_ acsrcs $ \(AddCSrc csrc _) ->
for_ acsrcs $ \(AddCSrc csrc _) ->
copyFileWithMD5Check (wdir </> csrc) (ddir </> csrc)


216 changes: 146 additions & 70 deletions fficxx/lib/FFICXX/Generate/Code/Cabal.hs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}

{-# LANGUAGE RecordWildCards #-}
-----------------------------------------------------------------------------
-- |
-- Module : FFICXX.Generate.Code.Cabal
@@ -14,28 +14,38 @@

module FFICXX.Generate.Code.Cabal where

import Data.Aeson.Encode.Pretty (encodePretty)
import qualified Data.ByteString.Lazy as BL
import Data.List (intercalate,nub)
import Data.Monoid ((<>))
import Data.Text (Text)
import Data.Text.Template (substitute)
import qualified Data.Text as T (intercalate,pack,replicate,unlines)
import qualified Data.Text.Lazy as TL (toStrict)
import qualified Data.Text.IO as TIO (writeFile)
import System.FilePath ((<.>),(</>))
--
import FFICXX.Generate.Type.Cabal (AddCInc(..),AddCSrc(..),CabalName(..),Cabal(..))
import FFICXX.Generate.Type.Cabal (AddCInc(..),AddCSrc(..)
,CabalName(..),Cabal(..)
,GeneratedCabalInfo(..))
import FFICXX.Generate.Type.Module
import FFICXX.Generate.Type.PackageInterface
import FFICXX.Generate.Util


cabalIndentation :: String
cabalIndentation = replicate 23 ' '
cabalIndentation :: Text -- String
cabalIndentation = T.replicate 23 " "


unlinesWithIndent = T.unlines . map (cabalIndentation <>)

-- for source distribution
genCsrcFiles :: (TopLevelImportHeader,[ClassModule])
-> [AddCInc]
-> [AddCSrc]
-> String
-> [String]
genCsrcFiles (tih,cmods) acincs acsrcs =
let indent = cabalIndentation
let -- indent = cabalIndentation
selfheaders' = do
x <- cmods
y <- cmCIH x
@@ -48,70 +58,79 @@ genCsrcFiles (tih,cmods) acincs acsrcs =
selfcpp = nub selfcpp'
tlh = tihHeaderFileName tih <.> "h"
tlcpp = tihHeaderFileName tih <.> "cpp"
includeFileStrsWithCsrc = map (\x->indent<>"csrc"</> x) $
includeFileStrsWithCsrc = map (\x->"csrc"</> x) $
(if (null.tihFuncs) tih then map unHdrName selfheaders else tlh:(map unHdrName selfheaders))
++ map (\(AddCInc hdr _) -> hdr) acincs
cppFilesWithCsrc = map (\x->indent<>"csrc"</>x) $
cppFilesWithCsrc = map (\x->"csrc"</>x) $
(if (null.tihFuncs) tih then selfcpp else tlcpp:selfcpp)
++ map (\(AddCSrc src _) -> src) acsrcs


in unlines (includeFileStrsWithCsrc <> cppFilesWithCsrc)

in includeFileStrsWithCsrc <> cppFilesWithCsrc

-- for library
genIncludeFiles :: String -- ^ package name
-> ([ClassImportHeader],[TemplateClassImportHeader])
-> [AddCInc]
-> String
-> [String]
genIncludeFiles pkgname (cih,tcih) acincs =
let indent = cabalIndentation
let -- indent = cabalIndentation
selfheaders = map cihSelfHeader cih <> map tcihSelfHeader tcih
includeFileStrs = map ((indent<>).unHdrName) (selfheaders ++ map (\(AddCInc hdr _) -> HdrName hdr) acincs)
in unlines ((indent<>pkgname<>"Type.h") : includeFileStrs)
includeFileStrs = map unHdrName (selfheaders ++ map (\(AddCInc hdr _) -> HdrName hdr) acincs)
in (pkgname<>"Type.h") : includeFileStrs


-- unlines ((indent<>


-- for library
genCppFiles :: (TopLevelImportHeader,[ClassModule])
-> [AddCSrc]
-> String
-> [String]
genCppFiles (tih,cmods) acsrcs =
let indent = cabalIndentation
let -- indent = cabalIndentation
selfcpp' = do
x <- cmods
y <- cmCIH x
return (cihSelfCpp y)
selfcpp = nub selfcpp'
tlcpp = tihHeaderFileName tih <.> "cpp"
cppFileStrs = map (\x->indent<> "csrc" </> x) $
cppFileStrs = map (\x -> "csrc" </> x) $
(if (null.tihFuncs) tih then selfcpp else tlcpp:selfcpp)
++ map (\(AddCSrc src _) -> src) acsrcs
in unlines cppFileStrs
in cppFileStrs



-- | generate exposed module list in cabal file
genExposedModules :: String -> ([ClassModule],[TemplateClassModule]) -> String
genExposedModules :: String -> ([ClassModule],[TemplateClassModule]) -> [String]
genExposedModules summarymod (cmods,tmods) =
let indentspace = cabalIndentation
summarystrs = indentspace <> summarymod
cmodstrs = map ((\x->indentspace<>x).cmModule) cmods
rawType = map ((\x->indentspace<>x<>".RawType").cmModule) cmods
ffi = map ((\x->indentspace<>x<>".FFI").cmModule) cmods
interface= map ((\x->indentspace<>x<>".Interface").cmModule) cmods
cast = map ((\x->indentspace<>x<>".Cast").cmModule) cmods
implementation = map ((\x->indentspace<>x<>".Implementation").cmModule) cmods
template = map ((\x->indentspace<>x<>".Template").tcmModule) tmods
th = map ((\x->indentspace<>x<>".TH").tcmModule) tmods
in unlines ([summarystrs]<>cmodstrs<>rawType<>ffi<>interface<>cast<>implementation<>template<>th)
let -- indentspace = cabalIndentation
-- summarystrs = summarymod
cmodstrs = map cmModule cmods
rawType = map ((\x -> x <> ".RawType").cmModule) cmods
ffi = map ((\x -> x <> ".FFI").cmModule) cmods
interface= map ((\x-> x <> ".Interface").cmModule) cmods
cast = map ((\x-> x <> ".Cast").cmModule) cmods
implementation = map ((\x-> x <> ".Implementation").cmModule) cmods
template = map ((\x-> x <> ".Template").tcmModule) tmods
th = map ((\x-> x <> ".TH").tcmModule) tmods
in -- unlines
[summarymod]<>cmodstrs<>rawType<>ffi<>interface<>cast<>implementation<>template<>th

-- | generate other modules in cabal file
genOtherModules :: [ClassModule] -> String
genOtherModules _cmods = ""
genOtherModules :: [ClassModule] -> [String]
genOtherModules _cmods = [""]

-- | generate additional package dependencies.
genPkgDeps :: [CabalName] -> String
genPkgDeps cs = intercalate " " (map (\(CabalName c) -> ", " <> c) cs)
genPkgDeps :: [CabalName] -> [String]
genPkgDeps cs = [ "base > 4 && < 5"
, "fficxx >= 0.5"
, "fficxx-runtime >= 0.5"
, "template-haskell"
]
++ map unCabalName cs



-- |
@@ -142,7 +161,7 @@ cabalTemplate =
\ ghc-options: -Wall -funbox-strict-fields -fno-warn-unused-do-bind -fno-warn-orphans -fno-warn-unused-imports\n\
\ ghc-prof-options: -caf-all -auto-all\n\
\ cc-options: $ccOptions\n\
\ Build-Depends: base>4 && < 5, fficxx >= 0.3, fficxx-runtime >= 0.3, template-haskell$deps\n\
\ Build-Depends: $pkgdeps\n\
\ Exposed-Modules:\n\
\$exposedModules\n\
\ Other-Modules:\n\
@@ -156,15 +175,16 @@ cabalTemplate =
\ C-sources:\n\
\$cppFiles\n"

-- |
buildCabalFile


-- TODO: remove all T.pack after we switch over to Text
genCabalInfo
:: Cabal
-> String
-> PackageConfig
-> [String] -- ^ extra libs
-> FilePath
-> IO ()
buildCabalFile cabal summarymodule pkgconfig extralibs cabalfile = do
-> GeneratedCabalInfo
genCabalInfo cabal summarymodule pkgconfig extralibs =
let tih = pcfg_topLevelImportHeader pkgconfig
classmodules = pcfg_classModules pkgconfig
cih = pcfg_classImportHeaders pkgconfig
@@ -173,33 +193,89 @@ buildCabalFile cabal summarymodule pkgconfig extralibs cabalfile = do
acincs = pcfg_additional_c_incs pkgconfig
acsrcs = pcfg_additional_c_srcs pkgconfig
extrafiles = cabal_extrafiles cabal
txt = subst cabalTemplate
(context ([ ("licenseField", "license: " <> license)
| Just license <- [cabal_license cabal] ] <>
[ ("licenseFileField", "license-file: " <> licensefile)
| Just licensefile <- [cabal_licensefile cabal] ] <>
[ ("pkgname", unCabalName (cabal_pkgname cabal))
, ("version", cabal_version cabal)
, ("buildtype", "Simple")
, ("synopsis", "")
, ("description", "")
, ("homepage","")
, ("author","")
, ("maintainer","")
, ("category","")
, ("sourcerepository","")
, ("ccOptions","-std=c++14")
, ("deps", genPkgDeps (cabal_additional_pkgdeps cabal))
, ("extraFiles", concatMap (\x -> cabalIndentation <> x <> "\n") extrafiles)
, ("csrcFiles", genCsrcFiles (tih,classmodules) acincs acsrcs)
, ("includeFiles", genIncludeFiles (unCabalName (cabal_pkgname cabal)) (cih,tcih) acincs)
, ("cppFiles", genCppFiles (tih,classmodules) acsrcs)
, ("exposedModules", genExposedModules summarymodule (classmodules,tmods))
, ("otherModules", genOtherModules classmodules)
, ("extralibdirs", intercalate ", " $ cabal_extralibdirs cabal)
, ("extraincludedirs", intercalate ", " $ cabal_extraincludedirs cabal)
, ("extraLibraries", concatMap (", " <>) extralibs)
, ("cabalIndentation", cabalIndentation)
, ("pkgconfigDepends", intercalate ", " (cabal_pkg_config_depends cabal))
]))
writeFile cabalfile txt
in GeneratedCabalInfo {
gci_pkgname = T.pack (unCabalName (cabal_pkgname cabal))
, gci_version = T.pack (cabal_version cabal)
, gci_synopsis = ""
, gci_description = ""
, gci_homepage = ""
, gci_license = maybe "" T.pack (cabal_license cabal)
, gci_licenseFile = maybe "" T.pack (cabal_licensefile cabal)
, gci_author = ""
, gci_maintainer = ""
, gci_category = ""
, gci_buildtype = "Simple"
, gci_extraFiles = map T.pack extrafiles
, gci_csrcFiles = map T.pack $ genCsrcFiles (tih,classmodules) acincs acsrcs
, gci_sourcerepository = ""
, gci_ccOptions = ["-std=c++14"]
, gci_pkgdeps = map T.pack $ genPkgDeps (cabal_additional_pkgdeps cabal)
, gci_exposedModules = map T.pack $ genExposedModules summarymodule (classmodules,tmods)
, gci_otherModules = map T.pack $ genOtherModules classmodules
, gci_extraLibDirs = map T.pack $ cabal_extralibdirs cabal
, gci_extraLibraries = map T.pack extralibs
, gci_extraIncludeDirs = map T.pack $ cabal_extraincludedirs cabal
, gci_pkgconfigDepends = map T.pack $ cabal_pkg_config_depends cabal
, gci_includeFiles = map T.pack $ genIncludeFiles (unCabalName (cabal_pkgname cabal)) (cih,tcih) acincs
, gci_cppFiles = map T.pack $ genCppFiles (tih,classmodules) acsrcs
}


genCabalFile :: GeneratedCabalInfo -> Text
genCabalFile GeneratedCabalInfo {..} =
TL.toStrict $
substitute cabalTemplate $
contextT [ ("licenseField" , "license: " <> gci_license)
, ("licenseFileField", "license-file: " <> gci_licenseFile)
, ("pkgname" , gci_pkgname)
, ("version" , gci_version)
, ("buildtype" , gci_buildtype)
, ("synopsis" , gci_synopsis)
, ("description" , gci_description)
, ("homepage" , gci_homepage)
, ("author" , gci_author)
, ("maintainer" , gci_maintainer)
, ("category" , gci_category)
, ("sourcerepository", gci_sourcerepository)
, ("ccOptions" , T.intercalate " " gci_ccOptions)
, ("pkgdeps" , T.intercalate ", " gci_pkgdeps)
, ("extraFiles" , unlinesWithIndent gci_extraFiles)
, ("csrcFiles" , unlinesWithIndent gci_csrcFiles)
, ("includeFiles" , unlinesWithIndent gci_includeFiles)
, ("cppFiles" , unlinesWithIndent gci_cppFiles)
, ("exposedModules" , unlinesWithIndent gci_exposedModules)
, ("otherModules" , unlinesWithIndent gci_otherModules)
, ("extralibdirs" , T.intercalate ", " gci_extraLibDirs)
, ("extraincludedirs", T.intercalate ", " gci_extraIncludeDirs)
, ("extraLibraries" , T.intercalate ", " gci_extraLibraries)
, ("cabalIndentation", cabalIndentation)
, ("pkgconfigDepends", T.intercalate ", " gci_pkgconfigDepends)
]


-- |
buildCabalFile
:: Cabal
-> String
-> PackageConfig
-> [String] -- ^ Extra libs
-> FilePath -- ^ Cabal file path
-> IO ()
buildCabalFile cabal summarymodule pkgconfig extralibs cabalfile = do
let
cinfo = genCabalInfo cabal summarymodule pkgconfig extralibs
txt = genCabalFile cinfo
TIO.writeFile cabalfile txt


-- |
buildJSONFile
:: Cabal
-> String
-> PackageConfig
-> [String] -- ^ Extra libs
-> FilePath -- ^ JSON file path
-> IO ()
buildJSONFile cabal summarymodule pkgconfig extralibs jsonfile = do
let cinfo = genCabalInfo cabal summarymodule pkgconfig extralibs
BL.writeFile jsonfile (encodePretty cinfo)
76 changes: 62 additions & 14 deletions fficxx/lib/FFICXX/Generate/Type/Cabal.hs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{-# LANGUAGE DeriveGeneric #-}

-----------------------------------------------------------------------------
-- |
-- Module : FFICXX.Generate.Type.Cabal
@@ -12,24 +14,70 @@

module FFICXX.Generate.Type.Cabal where

import Data.Aeson (FromJSON(..),ToJSON(..)
,genericParseJSON,genericToJSON
,defaultOptions)
import Data.Aeson.Types (fieldLabelModifier)
import Data.Text (Text)
import GHC.Generics (Generic)

data AddCInc = AddCInc FilePath String

data AddCSrc = AddCSrc FilePath String

-- TODO: change String to Text
newtype CabalName = CabalName { unCabalName :: String }
deriving (Show,Eq,Ord)

data Cabal = Cabal { cabal_pkgname :: CabalName
, cabal_version :: String
, cabal_cheaderprefix :: String
, cabal_moduleprefix :: String
, cabal_additional_c_incs :: [AddCInc]
, cabal_additional_c_srcs :: [AddCSrc]
, cabal_additional_pkgdeps :: [CabalName]
, cabal_license :: Maybe String
, cabal_licensefile :: Maybe String
, cabal_extraincludedirs :: [FilePath]
, cabal_extralibdirs :: [FilePath]
, cabal_extrafiles :: [FilePath]
, cabal_pkg_config_depends :: [String]
}
-- TODO: change String to Text
data Cabal =
Cabal {
cabal_pkgname :: CabalName
, cabal_version :: String
, cabal_cheaderprefix :: String
, cabal_moduleprefix :: String
, cabal_additional_c_incs :: [AddCInc]
, cabal_additional_c_srcs :: [AddCSrc]
, cabal_additional_pkgdeps :: [CabalName]
, cabal_license :: Maybe String
, cabal_licensefile :: Maybe String
, cabal_extraincludedirs :: [FilePath]
, cabal_extralibdirs :: [FilePath]
, cabal_extrafiles :: [FilePath]
, cabal_pkg_config_depends :: [String]
}

data GeneratedCabalInfo =
GeneratedCabalInfo {
gci_pkgname :: Text
, gci_version :: Text
, gci_synopsis :: Text
, gci_description :: Text
, gci_homepage :: Text
, gci_license :: Text
, gci_licenseFile :: Text
, gci_author :: Text
, gci_maintainer :: Text
, gci_category :: Text
, gci_buildtype :: Text
, gci_extraFiles :: [Text]
, gci_csrcFiles :: [Text]
, gci_sourcerepository :: Text
, gci_ccOptions :: [Text]
, gci_pkgdeps :: [Text]
, gci_exposedModules :: [Text]
, gci_otherModules :: [Text]
, gci_extraLibDirs :: [Text]
, gci_extraLibraries :: [Text]
, gci_extraIncludeDirs :: [Text]
, gci_pkgconfigDepends :: [Text]
, gci_includeFiles :: [Text]
, gci_cppFiles :: [Text]
}
deriving (Show,Generic)

instance ToJSON GeneratedCabalInfo where
toJSON = genericToJSON defaultOptions {fieldLabelModifier = drop 4}

instance FromJSON GeneratedCabalInfo where
parseJSON = genericParseJSON defaultOptions {fieldLabelModifier = drop 4}
10 changes: 5 additions & 5 deletions fficxx/lib/FFICXX/Generate/Type/Class.hs
Original file line number Diff line number Diff line change
@@ -68,12 +68,12 @@ data Types = Void
| SelfType
| CT CTypes IsConst
| CPT CPPTypes IsConst
| TemplateApp TemplateAppInfo -- ^ like vector<float>*
| TemplateAppRef TemplateAppInfo -- ^ like vector<float>&
| TemplateAppMove TemplateAppInfo -- ^ like unique_ptr<float> (using std::move)
| TemplateType TemplateClass -- ^ template self? TODO: clarify this.
| TemplateApp TemplateAppInfo -- ^ like vector<float>*
| TemplateAppRef TemplateAppInfo -- ^ like vector<float>&
| TemplateAppMove TemplateAppInfo -- ^ like unique_ptr<float> (using std::move)
| TemplateType TemplateClass -- ^ template self? TODO: clarify this.
| TemplateParam String
| TemplateParamPointer String -- ^ this is A* with template<A>
| TemplateParamPointer String -- ^ this is A* with template<A>
deriving Show

-------------
16 changes: 12 additions & 4 deletions fficxx/lib/FFICXX/Generate/Util.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
-----------------------------------------------------------------------------
-- |
-- Module : FFICXX.Generate.Util
-- Copyright : (c) 2011-2016 Ian-Woo Kim
-- Copyright : (c) 2011-2018 Ian-Woo Kim
--
-- License : BSD3
-- Maintainer : Ian-Woo Kim <ianwookim@gmail.com>
@@ -16,8 +17,9 @@ module FFICXX.Generate.Util where
import Data.Char
import Data.List
import Data.List.Split
import Data.Monoid ( (<>) )
import Data.Text ( Text )
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Data.Text.Template
@@ -81,11 +83,17 @@ intercalateWithM f mapper x
| otherwise = return ""


-- TODO: deprecate this and use contextT
context :: [(Text,String)] -> Context
context assocs x = maybe err (T.pack) . lookup x $ assocs
where err = error $ "Could not find key: " <> (T.unpack x)


-- TODO: Rename this to context.
-- TODO: Proper error handling.
contextT :: [(Text,Text)] -> Context
contextT assocs x = fromMaybe err . lookup x $ assocs
where err = error $ T.unpack ("Could not find key: " <> x)

subst :: Text -> Context -> String
subst t c = TL.unpack (substitute t c)

2 changes: 1 addition & 1 deletion stdcxx-gen/default.nix
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@ in
{ mkDerivation, base, fficxx, fficxx-runtime, stdenv, template-haskell }:
mkDerivation {
pname = "stdcxx";
version = "0.0";
version = "0.5";
src = stdcxx-src;
libraryHaskellDepends = [
base fficxx fficxx-runtime template-haskell

0 comments on commit 73ffd58

Please sign in to comment.