Distribution/Simple/Build/Macros.hs

    -----------------------------------------------------------------------------
    -- |
    -- 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.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 pkg_descr lbi clbi = Z.render Z.Z
        { Z.zPackages        = map mkZPackage $ package pkg_descr : map getPid (componentPackageDeps clbi)
        , Z.zTools           =
            [ Z.ZTool
                { Z.ztoolName    = programId prog
                , Z.ztoolVersion = ver
                , Z.ztoolX       = major1
                , Z.ztoolY       = major2
                , Z.ztoolZ       = minor
                }
            | prog <- configuredPrograms $ withPrograms lbi
            , ver <- maybeToList (programVersion prog)
            , let (major1,major2,minor) = majorMinor ver
            ]
        , Z.zPackageKey      = case clbi of
            LibComponentLocalBuildInfo{} -> componentCompatPackageKey clbi
            _                            -> ""
        , Z.zComponentId     = prettyShow (componentComponentId clbi)
        , Z.zPackageVersion  = pkgVersion (package pkg_descr)
        , Z.zNotNull         = not . null
        , Z.zManglePkgName   = map fixchar . unPackageName
        , Z.zMangleStr       = map fixchar
        }
      where
        getPid (_, MungedPackageId (MungedPackageName pn _) 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
            PackageIdentifier pn 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 ver pkgids = Z.render Z.Z
        { Z.zPackages        = map mkZPackage pkgids
        , Z.zTools           = []
        , Z.zPackageKey      = ""
        , Z.zComponentId     = ""
        , Z.zPackageVersion  = ver
        , Z.zNotNull         = not . null
        , Z.zManglePkgName   = map fixchar . unPackageName
        , Z.zMangleStr       = map fixchar
        }

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

    majorMinor :: Version -> (String, String, String)
    majorMinor ver = case map show (versionNumbers ver) of
            []        -> ("0", "0", "0")
            [x]       -> (x,   "0", "0")
            [x,y]     -> (x,   y,   "0")
            (x:y:z:_) -> (x,   y,   z)

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