{-# LANGUAGE OverloadedStrings #-}
module FFICXX.Generate.Code.Cabal where
import Data.List ( intercalate, nub )
import Data.Monoid ( (<>) )
import Data.Text ( Text )
import System.FilePath ( (<.>), (</>) )
import FFICXX.Generate.Type.Class
import FFICXX.Generate.Type.Module
import FFICXX.Generate.Type.PackageInterface
import FFICXX.Generate.Util
cabalIndentation :: String
cabalIndentation = replicate 23 ' '
genCsrcFiles :: (TopLevelImportHeader,[ClassModule])
-> [AddCInc]
-> [AddCSrc]
-> String
genCsrcFiles (tih,cmods) acincs acsrcs =
let indent = cabalIndentation
selfheaders' = do
x <- cmods
y <- cmCIH x
return (cihSelfHeader y)
selfheaders = nub selfheaders'
selfcpp' = do
x <- cmods
y <- cmCIH x
return (cihSelfCpp y)
selfcpp = nub selfcpp'
tlh = tihHeaderFileName tih <.> "h"
tlcpp = tihHeaderFileName tih <.> "cpp"
includeFileStrsWithCsrc = map (\x->indent<>"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) $
(if (null.tihFuncs) tih then selfcpp else tlcpp:selfcpp)
++ map (\(AddCSrc src _) -> src) acsrcs
in unlines (includeFileStrsWithCsrc <> cppFilesWithCsrc)
genIncludeFiles :: String
-> ([ClassImportHeader],[TemplateClassImportHeader])
-> [AddCInc]
-> String
genIncludeFiles pkgname (cih,tcih) acincs =
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)
genCppFiles :: (TopLevelImportHeader,[ClassModule])
-> [AddCSrc]
-> String
genCppFiles (tih,cmods) acsrcs =
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) $
(if (null.tihFuncs) tih then selfcpp else tlcpp:selfcpp)
++ map (\(AddCSrc src _) -> src) acsrcs
in unlines cppFileStrs
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)
genOtherModules :: [ClassModule] -> String
genOtherModules _cmods = ""
cabalTemplate :: Text
cabalTemplate =
"Name: $pkgname\n\
\Version: $version\n\
\Synopsis: $synopsis\n\
\Description: $description\n\
\Homepage: $homepage\n\
\$licenseField\n\
\$licenseFileField\n\
\Author: $author\n\
\Maintainer: $maintainer\n\
\Category: $category\n\
\Tested-with: GHC >= 7.6\n\
\Build-Type: $buildtype\n\
\cabal-version: >=1.10\n\
\Extra-source-files:\n\
\$extraFiles\n\
\$csrcFiles\n\
\\n\
\$sourcerepository\n\
\\n\
\Library\n\
\ default-language: Haskell2010\n\
\ hs-source-dirs: src\n\
\ 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\
\ Exposed-Modules:\n\
\$exposedModules\n\
\ Other-Modules:\n\
\$otherModules\n\
\ extra-lib-dirs: $extralibdirs\n\
\ extra-libraries: stdc++ $extraLibraries\n\
\ Include-dirs: csrc $extraincludedirs\n\
\ Install-includes:\n\
\$includeFiles\n\
\ C-sources:\n\
\$cppFiles\n"
buildCabalFile :: (Cabal, CabalAttr)
-> String
-> PackageConfig
-> [String]
-> FilePath
-> IO ()
buildCabalFile (cabal, cabalattr) summarymodule pkgconfig extralibs cabalfile = do
let tih = pcfg_topLevelImportHeader pkgconfig
classmodules = pcfg_classModules pkgconfig
cih = pcfg_classImportHeaders pkgconfig
tmods = pcfg_templateClassModules pkgconfig
tcih = pcfg_templateClassImportHeaders pkgconfig
acincs = pcfg_additional_c_incs pkgconfig
acsrcs = pcfg_additional_c_srcs pkgconfig
extrafiles = cabalattr_extrafiles cabalattr
txt = subst cabalTemplate
(context ([ ("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")
, ("synopsis", "")
, ("description", "")
, ("homepage","")
, ("author","")
, ("maintainer","")
, ("category","")
, ("sourcerepository","")
, ("ccOptions","-std=c++14")
, ("deps", "")
, ("extraFiles", concatMap (\x -> cabalIndentation <> x <> "\n") extrafiles)
, ("csrcFiles", genCsrcFiles (tih,classmodules) acincs acsrcs)
, ("includeFiles", genIncludeFiles (cabal_pkgname cabal) (cih,tcih) acincs)
, ("cppFiles", genCppFiles (tih,classmodules) acsrcs)
, ("exposedModules", genExposedModules summarymodule (classmodules,tmods))
, ("otherModules", genOtherModules classmodules)
, ("extralibdirs", intercalate ", " $ cabalattr_extralibdirs cabalattr)
, ("extraincludedirs", intercalate ", " $ cabalattr_extraincludedirs cabalattr)
, ("extraLibraries", concatMap (", " <>) extralibs)
, ("cabalIndentation", cabalIndentation)
]))
writeFile cabalfile txt