module Development.CabalBundleCLib
( mainWithCLib
, module Development.CabalBundleCLib.Types
) where
import Data.Time.Clock (getCurrentTime)
import Development.CabalBundleCLib.Types
import qualified Distribution.Compat.Lens as Lens
import qualified Distribution.PackageDescription as Cabal hiding
(Flag)
import qualified Distribution.Simple as Cabal
import qualified Distribution.Simple.Setup as Cabal
import qualified Distribution.Types.BuildInfo.Lens as CabalLens
import qualified Distribution.Types.Library.Lens as CabalLens
import qualified Distribution.Types.LocalBuildInfo as Cabal
import qualified Distribution.Types.PackageDescription.Lens as CabalLens
import System.Directory (removeFile)
import System.FilePath ((</>))
import System.IO.Temp (writeTempFile)
mainWithCLib :: FilePath
-> [String]
-> [FilePath]
-> (BuildAction -> BuildDirs -> IO ())
-> IO ()
mainWithCLib cProjRoot bundledLibs bundledLibDirs builder =
Cabal.defaultMainWithHooks Cabal.simpleUserHooks
{ Cabal.confHook = customConfigure bundledLibs
, Cabal.postConf = \_ _ _ _ -> pure ()
, Cabal.buildHook = customBuild cProjRoot bundledLibs bundledLibDirs builder
}
customConfigure :: [String]
-> (Cabal.GenericPackageDescription, Cabal.HookedBuildInfo)
-> Cabal.ConfigFlags
-> IO Cabal.LocalBuildInfo
customConfigure bundledLibs gpkgDesc configFlags = do
lbi <- Cabal.confHook Cabal.simpleUserHooks gpkgDesc configFlags
let localPkgDescr = Cabal.localPkgDescr lbi
localPkgDescr' = Lens.over CabalLens.library updateLibrary localPkgDescr
pure $ lbi { Cabal.localPkgDescr = localPkgDescr' }
where
updateLibrary :: Maybe Cabal.Library -> Maybe Cabal.Library
updateLibrary = fmap $ Lens.over CabalLens.libBuildInfo updateBuildInfo
updateBuildInfo :: Cabal.BuildInfo -> Cabal.BuildInfo
updateBuildInfo bi = bi
{ Cabal.extraLibs = bundledLibs ++ Cabal.extraLibs bi
, Cabal.extraBundledLibs = bundledLibs ++ Cabal.extraBundledLibs bi
}
customBuild :: FilePath
-> [String]
-> [FilePath]
-> (BuildAction -> BuildDirs -> IO ())
-> Cabal.PackageDescription
-> Cabal.LocalBuildInfo
-> Cabal.UserHooks
-> Cabal.BuildFlags
-> IO ()
customBuild cProjRoot bundledLibs bundledLibDirs builder packageDesc localBuildInfo userHooks buildFlags = do
currentTime <- getCurrentTime
let versionInfo = "const char *clibver = \"" ++ show currentTime ++ "\";\n"
let buildDir = Cabal.buildDir localBuildInfo
clibVersionFile <- writeTempFile buildDir "clibver.c" versionInfo
let updateLibrary :: Cabal.Library -> Cabal.Library
updateLibrary lib =
let lib' = Lens.over (CabalLens.libBuildInfo . CabalLens.cSources) (clibVersionFile :) lib
lib'' = Lens.over (CabalLens.libBuildInfo . CabalLens.extraLibDirs)
((fmap (\dir -> buildDir </> dir) bundledLibDirs) ++) lib'
in Lens.over (CabalLens.libBuildInfo . CabalLens.extraLibs) (bundledLibs ++) lib''
let packageDesc' = Lens.over CabalLens.library (fmap updateLibrary) packageDesc
builder
(BuildActionBuild (getBuildMode localBuildInfo))
(BuildDirs cProjRoot (buildDir </> "clibbuild") buildDir)
simpleBuildHook packageDesc' localBuildInfo userHooks buildFlags
removeFile clibVersionFile
getBuildMode :: Cabal.LocalBuildInfo -> BuildMode
getBuildMode localBuildInfo =
case Cabal.configOptimization . Cabal.configFlags $ localBuildInfo of
Cabal.Flag level ->
case level of
Cabal.MaximumOptimisation -> BuildModeRelease
_ -> BuildModeDebug
_ -> BuildModeDebug
simpleBuildHook :: Cabal.PackageDescription
-> Cabal.LocalBuildInfo
-> Cabal.UserHooks
-> Cabal.BuildFlags
-> IO ()
simpleBuildHook = Cabal.buildHook Cabal.simpleUserHooks