module Data.GI.CodeGen.Cabal
( genCabalProject
, cabalConfig
, setupHs
, tryPkgConfig
) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*>))
#endif
import Control.Monad (forM_)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Data.Version (Version(..))
import qualified Data.Map as M
import qualified Data.Text as T
import Data.Text (Text)
import Text.Read
import Data.GI.CodeGen.API (GIRInfo(..))
import Data.GI.CodeGen.Code
import Data.GI.CodeGen.Config (Config(..))
import Data.GI.CodeGen.Overrides (cabalPkgVersion)
import Data.GI.CodeGen.PkgConfig (pkgConfigGetVersion)
import qualified Data.GI.CodeGen.ProjectInfo as PI
import Data.GI.CodeGen.Util (padTo, tshow)
import Paths_haskell_gi (version)
cabalConfig :: Text
cabalConfig = T.unlines ["optimization: False"]
setupHs :: Text
setupHs = T.unlines ["#!/usr/bin/env runhaskell",
"import Distribution.Simple",
"main = defaultMain"]
haskellGIAPIVersion :: Int
haskellGIAPIVersion = (head . versionBranch) version
minorVersion :: [Int] -> Int
minorVersion (_:y:_) = y
minorVersion v = error $ "Programming error: the haskell-gi version does not have at least two components: " ++ show v ++ "."
haskellGIMinor :: Int
haskellGIMinor = minorVersion (versionBranch version)
giModuleVersion :: Int -> Int -> Text
giModuleVersion major minor =
(T.intercalate "." . map tshow) [haskellGIAPIVersion, major, minor,
haskellGIMinor]
giNextMinor :: Int -> Int -> Text
giNextMinor major minor = (T.intercalate "." . map tshow)
[haskellGIAPIVersion, major, minor+1]
data PkgInfo = PkgInfo { pkgName :: Text
, pkgMajor :: Int
, pkgMinor :: Int
} deriving Show
tryPkgConfig :: GIRInfo -> Bool -> M.Map Text Text -> IO (Either Text PkgInfo)
tryPkgConfig gir verbose overridenNames = do
let name = girNSName gir
version = girNSVersion gir
packages = girPCPackages gir
pkgConfigGetVersion name version packages verbose overridenNames >>= \case
Just (n,v) ->
case readMajorMinor v of
Just (major, minor) ->
return $ Right (PkgInfo { pkgName = n
, pkgMajor = major
, pkgMinor = minor})
Nothing -> return $ Left $ "Cannot parse version \"" <> v <>
"\" for module " <> name
Nothing -> return $ Left $
"Could not determine the pkg-config name corresponding to \"" <> name <> "\".\n" <>
"Try adding an override with the proper package name:\n"
<> "pkg-config-name " <> name <> " [matching pkg-config name here]"
readMajorMinor :: Text -> Maybe (Int, Int)
readMajorMinor version =
case T.splitOn "." version of
(a:b:_) -> (,) <$> readMaybe (T.unpack a) <*> readMaybe (T.unpack b)
_ -> Nothing
genCabalProject :: (GIRInfo, PkgInfo) -> [(GIRInfo, PkgInfo)] ->
[Text] -> BaseVersion -> CodeGen ()
genCabalProject (gir, PkgInfo {pkgName = pcName, pkgMajor = major,
pkgMinor = minor})
deps exposedModules minBaseVersion = do
cfg <- config
let name = girNSName gir
line $ "-- Autogenerated, do not edit."
line $ padTo 20 "name:" <> "gi-" <> T.toLower name
let cabalVersion = fromMaybe (giModuleVersion major minor)
(cabalPkgVersion $ overrides cfg)
line $ padTo 20 "version:" <> cabalVersion
line $ padTo 20 "synopsis:" <> name
<> " bindings"
line $ padTo 20 "description:" <> "Bindings for " <> name
<> ", autogenerated by haskell-gi."
line $ padTo 20 "homepage:" <> PI.homepage
line $ padTo 20 "license:" <> PI.license
line $ padTo 20 "license-file:" <> "LICENSE"
line $ padTo 20 "author:" <> PI.authors
line $ padTo 20 "maintainer:" <> PI.maintainers
line $ padTo 20 "category:" <> PI.category
line $ padTo 20 "build-type:" <> "Simple"
line $ padTo 20 "cabal-version:" <> ">=1.10"
blank
line $ "library"
indent $ do
line $ padTo 20 "default-language:" <> PI.defaultLanguage
line $ padTo 20 "default-extensions:" <>
T.intercalate ", " PI.defaultExtensions
line $ padTo 20 "other-extensions:" <>
T.intercalate ", " PI.otherExtensions
line $ padTo 20 "ghc-options:" <> T.intercalate " " PI.ghcOptions
line $ padTo 20 "exposed-modules:" <> head exposedModules
forM_ (tail exposedModules) $ \mod ->
line $ padTo 20 "" <> mod
line $ padTo 20 "pkgconfig-depends:" <> pcName <> " >= " <>
tshow major <> "." <> tshow minor
line $ "build-depends:"
indent $ do
line $ "haskell-gi-base >= "
<> tshow haskellGIAPIVersion <> "." <> tshow haskellGIMinor
<> " && < " <> tshow (haskellGIAPIVersion + 1) <> ","
forM_ deps $ \(dep, PkgInfo _ depMajor depMinor) -> do
let depName = girNSName dep
line $ "gi-" <> T.toLower depName <> " >= "
<> giModuleVersion depMajor depMinor
<> " && < "
<> giNextMinor depMajor depMinor
<> ","
forM_ PI.standardDeps (line . (<> ","))
line $ "base >= " <> showBaseVersion minBaseVersion <> " && <5"