-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.Build.Macros
-- Copyright   :  Isaac Jones 2003-2005,
--                Ross Paterson 2006,
--                Duncan Coutts 2007-2008
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- Generating the Paths_pkgname module.
--
-- This is a module that Cabal generates for the benefit of packages. It
-- enables them to find their version number and find any installed data files
-- at runtime. This code should probably be split off into another module.
--
module Distribution.Simple.Build.PathsModule (
    generatePathsModule, pkgPathEnvVar
  ) where

import Distribution.Compat.Prelude
import Prelude ()

import Distribution.Package
import Distribution.PackageDescription
import Distribution.Simple.Compiler
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Utils          (shortRelativePath)
import Distribution.System
import Distribution.Version

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

-- ------------------------------------------------------------
-- * Building Paths_<pkg>.hs
-- ------------------------------------------------------------

generatePathsModule :: PackageDescription -> LocalBuildInfo -> ComponentLocalBuildInfo -> String
generatePathsModule :: PackageDescription
-> LocalBuildInfo -> ComponentLocalBuildInfo -> FilePath
generatePathsModule PackageDescription
pkg_descr LocalBuildInfo
lbi ComponentLocalBuildInfo
clbi = Z -> FilePath
Z.render Z.Z
    { zPackageName :: PackageName
Z.zPackageName                = PackageDescription -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageDescription
pkg_descr
    , zVersionDigits :: FilePath
Z.zVersionDigits              = [Int] -> FilePath
forall a. Show a => a -> FilePath
show ([Int] -> FilePath) -> [Int] -> FilePath
forall a b. (a -> b) -> a -> b
$ Version -> [Int]
versionNumbers (Version -> [Int]) -> Version -> [Int]
forall a b. (a -> b) -> a -> b
$ PackageDescription -> Version
forall pkg. Package pkg => pkg -> Version
packageVersion PackageDescription
pkg_descr
    , zSupportsCpp :: Bool
Z.zSupportsCpp                = Bool
supports_cpp
    , zSupportsNoRebindableSyntax :: Bool
Z.zSupportsNoRebindableSyntax = Bool
supports_rebindable_syntax
    , zSupportsNoMissingSafeHaskellMode :: Bool
Z.zSupportsNoMissingSafeHaskellMode = Bool
supports_missing_safehaskell
    , zAbsolute :: Bool
Z.zAbsolute                   = Bool
absolute
    , zRelocatable :: Bool
Z.zRelocatable                = LocalBuildInfo -> Bool
relocatable LocalBuildInfo
lbi
    , zIsWindows :: Bool
Z.zIsWindows                  = Bool
isWindows
    , zIsI386 :: Bool
Z.zIsI386                     = Arch
buildArch Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
== Arch
I386
    , zIsX8664 :: Bool
Z.zIsX8664                    = Arch
buildArch Arch -> Arch -> Bool
forall a. Eq a => a -> a -> Bool
== Arch
X86_64
    , zNot :: Bool -> Bool
Z.zNot                        = Bool -> Bool
not
    , zManglePkgName :: PackageName -> FilePath
Z.zManglePkgName              = PackageName -> FilePath
showPkgName

    , zPrefix :: FilePath
Z.zPrefix     = FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_prefix
    , zBindir :: FilePath
Z.zBindir     = FilePath
zBindir
    , zLibdir :: FilePath
Z.zLibdir     = FilePath
zLibdir
    , zDynlibdir :: FilePath
Z.zDynlibdir  = FilePath
zDynlibdir
    , zDatadir :: FilePath
Z.zDatadir    = FilePath
zDatadir
    , zLibexecdir :: FilePath
Z.zLibexecdir = FilePath
zLibexecdir
    , zSysconfdir :: FilePath
Z.zSysconfdir = FilePath
zSysconfdir
    }
  where
    supports_cpp :: Bool
supports_cpp                 = Bool
supports_language_pragma
    supports_rebindable_syntax :: Bool
supports_rebindable_syntax   = Version -> Bool
ghc_newer_than ([Int] -> Version
mkVersion [Int
7,Int
0,Int
1])
    supports_language_pragma :: Bool
supports_language_pragma     = Version -> Bool
ghc_newer_than ([Int] -> Version
mkVersion [Int
6,Int
6,Int
1])
    supports_missing_safehaskell :: Bool
supports_missing_safehaskell = Version -> Bool
ghc_newer_than ([Int] -> Version
mkVersion [Int
8,Int
10,Int
1])

    ghc_newer_than :: Version -> Bool
ghc_newer_than Version
minVersion =
        case CompilerFlavor -> Compiler -> Maybe Version
compilerCompatVersion CompilerFlavor
GHC (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi) of
            Maybe Version
Nothing      -> Bool
False
            Just Version
version -> Version
version Version -> VersionRange -> Bool
`withinRange` Version -> VersionRange
orLaterVersion Version
minVersion

    -- In several cases we cannot make relocatable installations
    absolute :: Bool
absolute =
         PackageDescription -> Bool
hasLibs PackageDescription
pkg_descr        -- we can only make progs relocatable
      Bool -> Bool -> Bool
|| Maybe FilePath -> Bool
forall a. Maybe a -> Bool
isNothing Maybe FilePath
flat_bindirrel -- if the bin dir is an absolute path
      Bool -> Bool -> Bool
|| Bool -> Bool
not (CompilerFlavor -> Bool
supportsRelocatableProgs (Compiler -> CompilerFlavor
compilerFlavor (LocalBuildInfo -> Compiler
compiler LocalBuildInfo
lbi)))

    -- TODO: Here, and with zIsI386 & zIs8664 we should use TARGET platform
    isWindows :: Bool
isWindows = case OS
buildOS of
        OS
Windows   -> Bool
True
        OS
_         -> Bool
False

    supportsRelocatableProgs :: CompilerFlavor -> Bool
supportsRelocatableProgs CompilerFlavor
GHC   = Bool
isWindows
    supportsRelocatableProgs CompilerFlavor
GHCJS = Bool
isWindows
    supportsRelocatableProgs CompilerFlavor
_     = Bool
False

    cid :: UnitId
cid = ComponentLocalBuildInfo -> UnitId
componentUnitId ComponentLocalBuildInfo
clbi

    InstallDirs
        { bindir :: forall dir. InstallDirs dir -> dir
bindir     = FilePath
flat_bindir
        , libdir :: forall dir. InstallDirs dir -> dir
libdir     = FilePath
flat_libdir
        , dynlibdir :: forall dir. InstallDirs dir -> dir
dynlibdir  = FilePath
flat_dynlibdir
        , datadir :: forall dir. InstallDirs dir -> dir
datadir    = FilePath
flat_datadir
        , libexecdir :: forall dir. InstallDirs dir -> dir
libexecdir = FilePath
flat_libexecdir
        , sysconfdir :: forall dir. InstallDirs dir -> dir
sysconfdir = FilePath
flat_sysconfdir
        , prefix :: forall dir. InstallDirs dir -> dir
prefix     = FilePath
flat_prefix
        } = PackageDescription
-> LocalBuildInfo -> UnitId -> CopyDest -> InstallDirs FilePath
absoluteInstallCommandDirs PackageDescription
pkg_descr LocalBuildInfo
lbi UnitId
cid CopyDest
NoCopyDest

    InstallDirs
        { bindir :: forall dir. InstallDirs dir -> dir
bindir     = Maybe FilePath
flat_bindirrel
        , libdir :: forall dir. InstallDirs dir -> dir
libdir     = Maybe FilePath
flat_libdirrel
        , dynlibdir :: forall dir. InstallDirs dir -> dir
dynlibdir  = Maybe FilePath
flat_dynlibdirrel
        , datadir :: forall dir. InstallDirs dir -> dir
datadir    = Maybe FilePath
flat_datadirrel
        , libexecdir :: forall dir. InstallDirs dir -> dir
libexecdir = Maybe FilePath
flat_libexecdirrel
        , sysconfdir :: forall dir. InstallDirs dir -> dir
sysconfdir = Maybe FilePath
flat_sysconfdirrel
        } = PackageId
-> LocalBuildInfo -> UnitId -> InstallDirs (Maybe FilePath)
prefixRelativeComponentInstallDirs (PackageDescription -> PackageId
forall pkg. Package pkg => pkg -> PackageId
packageId PackageDescription
pkg_descr) LocalBuildInfo
lbi UnitId
cid

    zBindir, zLibdir, zDynlibdir, zDatadir, zLibexecdir, zSysconfdir :: String
    (FilePath
zBindir, FilePath
zLibdir, FilePath
zDynlibdir, FilePath
zDatadir, FilePath
zLibexecdir, FilePath
zSysconfdir)
        | LocalBuildInfo -> Bool
relocatable LocalBuildInfo
lbi =
            ( FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_bindir_reloc
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_libdir_reloc
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_dynlibdir_reloc
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_datadir_reloc
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_libexecdir_reloc
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_sysconfdir_reloc
            )
        | Bool
absolute        =
            ( FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_bindir
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_libdir
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_dynlibdir
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_datadir
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_libexecdir
            , FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
flat_sysconfdir
            )
        | Bool
isWindows       =
            ( FilePath
"maybe (error \"PathsModule.generate\") id (" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Maybe FilePath -> FilePath
forall a. Show a => a -> FilePath
show Maybe FilePath
flat_bindirrel FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
")"
            , FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
flat_libdir Maybe FilePath
flat_libdirrel
            , FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
flat_dynlibdir Maybe FilePath
flat_dynlibdirrel
            , FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
flat_datadir Maybe FilePath
flat_datadirrel
            , FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
flat_libexecdir Maybe FilePath
flat_libexecdirrel
            , FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
flat_sysconfdir Maybe FilePath
flat_sysconfdirrel
            )
        | Bool
otherwise       =
            FilePath
-> (FilePath, FilePath, FilePath, FilePath, FilePath, FilePath)
forall a. HasCallStack => FilePath -> a
error FilePath
"panic! generatePathsModule: should never happen"

    mkGetDir :: FilePath -> Maybe FilePath -> String
    mkGetDir :: FilePath -> Maybe FilePath -> FilePath
mkGetDir FilePath
_   (Just FilePath
dirrel) = FilePath
"getPrefixDirRel " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
dirrel
    mkGetDir FilePath
dir Maybe FilePath
Nothing       = FilePath
"return " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath -> FilePath
forall a. Show a => a -> FilePath
show FilePath
dir

    flat_bindir_reloc :: FilePath
flat_bindir_reloc     = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_bindir
    flat_libdir_reloc :: FilePath
flat_libdir_reloc     = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_libdir
    flat_dynlibdir_reloc :: FilePath
flat_dynlibdir_reloc  = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_dynlibdir
    flat_datadir_reloc :: FilePath
flat_datadir_reloc    = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_datadir
    flat_libexecdir_reloc :: FilePath
flat_libexecdir_reloc = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_libexecdir
    flat_sysconfdir_reloc :: FilePath
flat_sysconfdir_reloc = FilePath -> FilePath -> FilePath
shortRelativePath FilePath
flat_prefix FilePath
flat_sysconfdir

-- | Generates the name of the environment variable controlling the path
-- component of interest.
--
-- Note: The format of these strings is part of Cabal's public API;
-- changing this function constitutes a *backwards-compatibility* break.
pkgPathEnvVar
    :: PackageDescription
    -> String     -- ^ path component; one of \"bindir\", \"libdir\", -- \"datadir\", \"libexecdir\", or \"sysconfdir\"
    -> String     -- ^ environment variable name
pkgPathEnvVar :: PackageDescription -> FilePath -> FilePath
pkgPathEnvVar PackageDescription
pkg_descr FilePath
var =
    PackageName -> FilePath
showPkgName (PackageDescription -> PackageName
forall pkg. Package pkg => pkg -> PackageName
packageName PackageDescription
pkg_descr) FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
"_" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ FilePath
var

showPkgName :: PackageName -> String
showPkgName :: PackageName -> FilePath
showPkgName = (Char -> Char) -> FilePath -> FilePath
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
fixchar (FilePath -> FilePath)
-> (PackageName -> FilePath) -> PackageName -> FilePath
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageName -> FilePath
unPackageName

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