{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Distribution.Types.ForeignLib(
ForeignLib(..),
emptyForeignLib,
foreignLibModules,
foreignLibIsShared,
foreignLibVersion,
LibVersionInfo,
mkLibVersionInfo,
libVersionInfoCRA,
libVersionNumber,
libVersionNumberShow,
libVersionMajor
) where
import Distribution.Compat.Prelude
import Prelude ()
import Distribution.ModuleName
import Distribution.Parsec.Class
import Distribution.Pretty
import Distribution.System
import Distribution.Text
import Distribution.Types.BuildInfo
import Distribution.Types.ForeignLibOption
import Distribution.Types.ForeignLibType
import Distribution.Types.UnqualComponentName
import Distribution.Version
import qualified Distribution.Compat.CharParsing as P
import qualified Distribution.Compat.ReadP as Parse
import qualified Text.PrettyPrint as Disp
import qualified Text.Read as Read
import qualified Distribution.Types.BuildInfo.Lens as L
data ForeignLib = ForeignLib {
foreignLibName :: UnqualComponentName
, foreignLibType :: ForeignLibType
, foreignLibOptions :: [ForeignLibOption]
, foreignLibBuildInfo :: BuildInfo
, foreignLibVersionInfo :: Maybe LibVersionInfo
, foreignLibVersionLinux :: Maybe Version
, foreignLibModDefFile :: [FilePath]
}
deriving (Generic, Show, Read, Eq, Typeable, Data)
data LibVersionInfo = LibVersionInfo Int Int Int deriving (Data, Eq, Generic, Typeable)
instance Ord LibVersionInfo where
LibVersionInfo c r _ `compare` LibVersionInfo c' r' _ =
case c `compare` c' of
EQ -> r `compare` r'
e -> e
instance Show LibVersionInfo where
showsPrec d (LibVersionInfo c r a) = showParen (d > 10)
$ showString "mkLibVersionInfo "
. showsPrec 11 (c,r,a)
instance Read LibVersionInfo where
readPrec = Read.parens $ do
Read.Ident "mkLibVersionInfo" <- Read.lexP
t <- Read.step Read.readPrec
return (mkLibVersionInfo t)
instance Binary LibVersionInfo
instance NFData LibVersionInfo where rnf = genericRnf
instance Pretty LibVersionInfo where
pretty (LibVersionInfo c r a)
= Disp.hcat $ Disp.punctuate (Disp.char ':') $ map Disp.int [c,r,a]
instance Parsec LibVersionInfo where
parsec = do
c <- P.integral
(r, a) <- P.option (0,0) $ do
_ <- P.char ':'
r <- P.integral
a <- P.option 0 $ do
_ <- P.char ':'
P.integral
return (r,a)
return $ mkLibVersionInfo (c,r,a)
instance Text LibVersionInfo where
parse = do
c <- parseNat
(r, a) <- Parse.option (0,0) $ do
_ <- Parse.char ':'
r <- parseNat
a <- Parse.option 0 (Parse.char ':' >> parseNat)
return (r, a)
return $ mkLibVersionInfo (c,r,a)
where
parseNat = read `fmap` Parse.munch1 isDigit
mkLibVersionInfo :: (Int, Int, Int) -> LibVersionInfo
mkLibVersionInfo (c,r,a) = LibVersionInfo c r a
libVersionInfoCRA :: LibVersionInfo -> (Int, Int, Int)
libVersionInfoCRA (LibVersionInfo c r a) = (c,r,a)
libVersionNumber :: LibVersionInfo -> (Int, Int, Int)
libVersionNumber (LibVersionInfo c r a) = (c-a , a , r)
libVersionNumberShow :: LibVersionInfo -> String
libVersionNumberShow v =
let (major, minor, build) = libVersionNumber v
in show major ++ "." ++ show minor ++ "." ++ show build
libVersionMajor :: LibVersionInfo -> Int
libVersionMajor (LibVersionInfo c _ a) = c-a
instance L.HasBuildInfo ForeignLib where
buildInfo f l = (\x -> l { foreignLibBuildInfo = x }) <$> f (foreignLibBuildInfo l)
instance Binary ForeignLib
instance NFData ForeignLib where rnf = genericRnf
instance Semigroup ForeignLib where
a <> b = ForeignLib {
foreignLibName = combine' foreignLibName
, foreignLibType = combine foreignLibType
, foreignLibOptions = combine foreignLibOptions
, foreignLibBuildInfo = combine foreignLibBuildInfo
, foreignLibVersionInfo = combine'' foreignLibVersionInfo
, foreignLibVersionLinux = combine'' foreignLibVersionLinux
, foreignLibModDefFile = combine foreignLibModDefFile
}
where combine field = field a `mappend` field b
combine' field = case ( unUnqualComponentName $ field a
, unUnqualComponentName $ field b) of
("", _) -> field b
(_, "") -> field a
(x, y) -> error $ "Ambiguous values for executable field: '"
++ x ++ "' and '" ++ y ++ "'"
combine'' field = field b
instance Monoid ForeignLib where
mempty = ForeignLib {
foreignLibName = mempty
, foreignLibType = ForeignLibTypeUnknown
, foreignLibOptions = []
, foreignLibBuildInfo = mempty
, foreignLibVersionInfo = Nothing
, foreignLibVersionLinux = Nothing
, foreignLibModDefFile = []
}
mappend = (<>)
emptyForeignLib :: ForeignLib
emptyForeignLib = mempty
foreignLibModules :: ForeignLib -> [ModuleName]
foreignLibModules = otherModules . foreignLibBuildInfo
foreignLibIsShared :: ForeignLib -> Bool
foreignLibIsShared = foreignLibTypeIsShared . foreignLibType
foreignLibVersion :: ForeignLib -> OS -> [Int]
foreignLibVersion flib Linux =
case foreignLibVersionLinux flib of
Just v -> versionNumbers v
Nothing ->
case foreignLibVersionInfo flib of
Just v' ->
let (major, minor, build) = libVersionNumber v'
in [major, minor, build]
Nothing -> []
foreignLibVersion _ _ = []