-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.Build.Macros
-- Copyright   :  Simon Marlow 2008
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- Generate cabal_macros.h - CPP macros for package version testing
--
-- When using CPP you get
--
-- > VERSION_<package>
-- > MIN_VERSION_<package>(A,B,C)
--
-- for each /package/ in @build-depends@, which is true if the version of
-- /package/ in use is @>= A.B.C@, using the normal ordering on version
-- numbers.
--
-- TODO Figure out what to do about backpack and internal libraries. It is very
-- suspecious that this stuff works with munged package identifiers
module Distribution.Simple.Build.Macros (
    generateCabalMacrosHeader,
    generatePackageVersionMacros,
  ) where

import Prelude ()
import Distribution.Compat.Prelude

import Distribution.Version
import Distribution.PackageDescription
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Program.Db
import Distribution.Simple.Program.Types
import Distribution.Types.MungedPackageId
import Distribution.Types.MungedPackageName
import Distribution.Types.PackageId
import Distribution.Types.PackageName (unPackageName)
import Distribution.Pretty

import qualified Distribution.Simple.Build.Macros.Z as Z

-- | The contents of the @cabal_macros.h@ for the given configured package.
--
generateCabalMacrosHeader :: PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> String
generateCabalMacrosHeader :: PackageDescription
-> LocalBuildInfo -> ComponentLocalBuildInfo -> String
generateCabalMacrosHeader PackageDescription
pkg_descr LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi = Z -> String
Z.render Z :: [ZPackage]
-> [ZTool]
-> String
-> String
-> Version
-> (String -> Bool)
-> (PackageName -> String)
-> (String -> String)
-> Z
Z.Z
    { zPackages :: [ZPackage]
Z.zPackages        = (PackageId -> ZPackage) -> [PackageId] -> [ZPackage]
forall a b. (a -> b) -> [a] -> [b]
map PackageId -> ZPackage
mkZPackage ([PackageId] -> [ZPackage]) -> [PackageId] -> [ZPackage]
forall a b. (a -> b) -> a -> b
$ PackageDescription -> PackageId
package PackageDescription
pkg_descr PackageId -> [PackageId] -> [PackageId]
forall a. a -> [a] -> [a]
: ((UnitId, MungedPackageId) -> PackageId)
-> [(UnitId, MungedPackageId)] -> [PackageId]
forall a b. (a -> b) -> [a] -> [b]
map (UnitId, MungedPackageId) -> PackageId
forall {a}. (a, MungedPackageId) -> PackageId
getPid (ComponentLocalBuildInfo -> [(UnitId, MungedPackageId)]
componentPackageDeps ComponentLocalBuildInfo
clbi)
    , zTools :: [ZTool]
Z.zTools           =
        [ ZTool :: String -> Version -> String -> String -> String -> ZTool
Z.ZTool
            { ztoolName :: String
Z.ztoolName    = ConfiguredProgram -> String
programId ConfiguredProgram
prog
            , ztoolVersion :: Version
Z.ztoolVersion = Version
ver
            , ztoolX :: String
Z.ztoolX       = String
major1
            , ztoolY :: String
Z.ztoolY       = String
major2
            , ztoolZ :: String
Z.ztoolZ       = String
minor
            }
        | ConfiguredProgram
prog <- ProgramDb -> [ConfiguredProgram]
configuredPrograms (ProgramDb -> [ConfiguredProgram])
-> ProgramDb -> [ConfiguredProgram]
forall a b. (a -> b) -> a -> b
$ LocalBuildInfo -> ProgramDb
withPrograms LocalBuildInfo
lbi
        , Version
ver <- Maybe Version -> [Version]
forall a. Maybe a -> [a]
maybeToList (ConfiguredProgram -> Maybe Version
programVersion ConfiguredProgram
prog)
        , let (String
major1,String
major2,String
minor) = Version -> (String, String, String)
majorMinor Version
ver
        ]
    , zPackageKey :: String
Z.zPackageKey      = case ComponentLocalBuildInfo
clbi of
        LibComponentLocalBuildInfo{} -> ComponentLocalBuildInfo -> String
componentCompatPackageKey ComponentLocalBuildInfo
clbi
        ComponentLocalBuildInfo
_                            -> String
""
    , zComponentId :: String
Z.zComponentId     = ComponentId -> String
forall a. Pretty a => a -> String
External instance of the constraint type Pretty ComponentId
prettyShow (ComponentLocalBuildInfo -> ComponentId
componentComponentId ComponentLocalBuildInfo
clbi)
    , zPackageVersion :: Version
Z.zPackageVersion  = PackageId -> Version
pkgVersion (PackageDescription -> PackageId
package PackageDescription
pkg_descr)
    , zNotNull :: String -> Bool
Z.zNotNull         = Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
External instance of the constraint type Foldable []
null
    , zManglePkgName :: PackageName -> String
Z.zManglePkgName   = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
fixchar (String -> String)
-> (PackageName -> String) -> PackageName -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> String
unPackageName
    , zMangleStr :: String -> String
Z.zMangleStr       = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
fixchar
    }
  where
    getPid :: (a, MungedPackageId) -> PackageId
getPid (a
_, MungedPackageId (MungedPackageName PackageName
pn LibraryName
_) Version
v) =
       -- NB: Drop the library name! We're just reporting package versions.
       -- This would have to be revisited if you are allowed to depend
       -- on different versions of the same package
        PackageName -> Version -> PackageId
PackageIdentifier PackageName
pn Version
v

-- | Helper function that generates just the @VERSION_pkg@ and @MIN_VERSION_pkg@
-- macros for a list of package ids (usually used with the specific deps of
-- a configured package).
--
generatePackageVersionMacros :: Version -> [PackageId] -> String
generatePackageVersionMacros :: Version -> [PackageId] -> String
generatePackageVersionMacros Version
ver [PackageId]
pkgids = Z -> String
Z.render Z :: [ZPackage]
-> [ZTool]
-> String
-> String
-> Version
-> (String -> Bool)
-> (PackageName -> String)
-> (String -> String)
-> Z
Z.Z
    { zPackages :: [ZPackage]
Z.zPackages        = (PackageId -> ZPackage) -> [PackageId] -> [ZPackage]
forall a b. (a -> b) -> [a] -> [b]
map PackageId -> ZPackage
mkZPackage [PackageId]
pkgids
    , zTools :: [ZTool]
Z.zTools           = []
    , zPackageKey :: String
Z.zPackageKey      = String
""
    , zComponentId :: String
Z.zComponentId     = String
""
    , zPackageVersion :: Version
Z.zPackageVersion  = Version
ver
    , zNotNull :: String -> Bool
Z.zNotNull         = Bool -> Bool
not (Bool -> Bool) -> (String -> Bool) -> String -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
External instance of the constraint type Foldable []
null
    , zManglePkgName :: PackageName -> String
Z.zManglePkgName   = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
fixchar (String -> String)
-> (PackageName -> String) -> PackageName -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> String
unPackageName
    , zMangleStr :: String -> String
Z.zMangleStr       = (Char -> Char) -> String -> String
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
fixchar
    }

mkZPackage :: PackageId -> Z.ZPackage
mkZPackage :: PackageId -> ZPackage
mkZPackage (PackageIdentifier PackageName
name Version
ver) = ZPackage :: PackageName -> Version -> String -> String -> String -> ZPackage
Z.ZPackage
    { zpkgName :: PackageName
Z.zpkgName    = PackageName
name
    , zpkgVersion :: Version
Z.zpkgVersion = Version
ver
    , zpkgX :: String
Z.zpkgX       = String
major1
    , zpkgY :: String
Z.zpkgY       = String
major2
    , zpkgZ :: String
Z.zpkgZ       = String
minor
    }
  where
    (String
major1,String
major2,String
minor) = Version -> (String, String, String)
majorMinor Version
ver

majorMinor :: Version -> (String, String, String)
majorMinor :: Version -> (String, String, String)
majorMinor Version
ver = case (Int -> String) -> [Int] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map Int -> String
forall a. Show a => a -> String
External instance of the constraint type Show Int
show (Version -> [Int]
versionNumbers Version
ver) of
        []        -> (String
"0", String
"0", String
"0")
        [String
x]       -> (String
x,   String
"0", String
"0")
        [String
x,String
y]     -> (String
x,   String
y,   String
"0")
        (String
x:String
y:String
z:[String]
_) -> (String
x,   String
y,   String
z)

fixchar :: Char -> Char
fixchar :: Char -> Char
fixchar Char
'-' = Char
'_'
fixchar Char
c   = Char
c