-----------------------------------------------------------------------------
-- |
-- 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.
--
module Distribution.Simple.Build.Macros (
    generate,
    generatePackageVersionMacros,
  ) where

import Distribution.Package
         ( PackageIdentifier(PackageIdentifier) )
import Distribution.Version
         ( Version(versionBranch) )
import Distribution.PackageDescription
         ( PackageDescription )
import Distribution.Simple.LocalBuildInfo
        ( LocalBuildInfo, externalPackageDeps )
import Distribution.Text
         ( display )

-- ------------------------------------------------------------
-- * Generate cabal_macros.h
-- ------------------------------------------------------------

-- | The contents of the @cabal_macros.h@ for the given configured package.
--
generate :: PackageDescription -> LocalBuildInfo -> String
generate _pkg_descr lbi =
  "/* DO NOT EDIT: This file is automatically generated by Cabal */\n\n" ++
  generatePackageVersionMacros (map snd (externalPackageDeps lbi))


-- | 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 :: [PackageIdentifier] -> String
generatePackageVersionMacros pkgids = concat
  [ concat
    ["/* package ",display pkgid," */\n"
    ,"#define VERSION_",pkgname," ",show (display version),"\n"
    ,"#define MIN_VERSION_",pkgname,"(major1,major2,minor) (\\\n"
    ,"  (major1) <  ",major1," || \\\n"
    ,"  (major1) == ",major1," && (major2) <  ",major2," || \\\n"
    ,"  (major1) == ",major1," && (major2) == ",major2," && (minor) <= ",minor,")"
    ,"\n\n"
    ]
  | pkgid@(PackageIdentifier name version) <- pkgids
  , let (major1:major2:minor:_) = map show (versionBranch version ++ repeat 0)
        pkgname = map fixchar (display name)
  ]
  where fixchar '-' = '_'
        fixchar c   = c