module Distribution.Simple.JHC (
configure, getInstalledPackages,
buildLib, buildExe,
installLib, installExe
) where
import Distribution.PackageDescription as PD
( PackageDescription(..), BuildInfo(..), Executable(..)
, Library(..), libModules, hcOptions, usedExtensions )
import Distribution.InstalledPackageInfo
( emptyInstalledPackageInfo, )
import qualified Distribution.InstalledPackageInfo as InstalledPackageInfo
import Distribution.Simple.PackageIndex (InstalledPackageIndex)
import qualified Distribution.Simple.PackageIndex as PackageIndex
import Distribution.Simple.LocalBuildInfo
( LocalBuildInfo(..), ComponentLocalBuildInfo(..) )
import Distribution.Simple.BuildPaths
( autogenModulesDir, exeExtension )
import Distribution.Simple.Compiler
( CompilerFlavor(..), CompilerId(..), Compiler(..), AbiTag(..)
, PackageDBStack, Flag, languageToFlags, extensionsToFlags )
import Language.Haskell.Extension
( Language(Haskell98), Extension(..), KnownExtension(..))
import Distribution.Simple.Program
( ConfiguredProgram(..), jhcProgram, ProgramConfiguration
, userMaybeSpecifyPath, requireProgramVersion, lookupProgram
, rawSystemProgram, rawSystemProgramStdoutConf )
import Distribution.Version
( Version(..), orLaterVersion )
import Distribution.Package
( Package(..), InstalledPackageId(InstalledPackageId),
pkgName, pkgVersion, )
import Distribution.Simple.Utils
( createDirectoryIfMissingVerbose, writeFileAtomic
, installOrdinaryFile, installExecutableFile
, intercalate )
import System.FilePath ( (</>) )
import Distribution.Verbosity
import Distribution.Text
( Text(parse), display )
import Distribution.Compat.ReadP
( readP_to_S, string, skipSpaces )
import Distribution.System ( Platform )
import Data.List ( nub )
import Data.Char ( isSpace )
import qualified Data.Map as M ( empty )
import Data.Maybe ( fromMaybe )
import qualified Data.ByteString.Lazy.Char8 as BS.Char8
configure :: Verbosity -> Maybe FilePath -> Maybe FilePath
-> ProgramConfiguration -> IO (Compiler, Maybe Platform, ProgramConfiguration)
configure verbosity hcPath _hcPkgPath conf = do
(jhcProg, _, conf') <- requireProgramVersion verbosity
jhcProgram (orLaterVersion (Version [0,7,2] []))
(userMaybeSpecifyPath "jhc" hcPath conf)
let Just version = programVersion jhcProg
comp = Compiler {
compilerId = CompilerId JHC version,
compilerAbiTag = NoAbiTag,
compilerCompat = [],
compilerLanguages = jhcLanguages,
compilerExtensions = jhcLanguageExtensions,
compilerProperties = M.empty
}
compPlatform = Nothing
return (comp, compPlatform, conf')
jhcLanguages :: [(Language, Flag)]
jhcLanguages = [(Haskell98, "")]
jhcLanguageExtensions :: [(Extension, Flag)]
jhcLanguageExtensions =
[(EnableExtension TypeSynonymInstances , "")
,(DisableExtension TypeSynonymInstances , "")
,(EnableExtension ForeignFunctionInterface , "")
,(DisableExtension ForeignFunctionInterface , "")
,(EnableExtension ImplicitPrelude , "")
,(DisableExtension ImplicitPrelude , "--noprelude")
,(EnableExtension CPP , "-fcpp")
,(DisableExtension CPP , "-fno-cpp")
]
getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration
-> IO InstalledPackageIndex
getInstalledPackages verbosity _packageDBs conf = do
str <- rawSystemProgramStdoutConf verbosity jhcProgram conf ["--list-libraries"]
let pCheck :: [(a, String)] -> [a]
pCheck rs = [ r | (r,s) <- rs, all isSpace s ]
let parseLine ln =
pCheck (readP_to_S
(skipSpaces >> string "Name:" >> skipSpaces >> parse) ln)
return $
PackageIndex.fromList $
map (\p -> emptyInstalledPackageInfo {
InstalledPackageInfo.installedPackageId =
InstalledPackageId (display p),
InstalledPackageInfo.sourcePackageId = p
}) $
concatMap parseLine $
lines str
buildLib :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Library -> ComponentLocalBuildInfo -> IO ()
buildLib verbosity pkg_descr lbi lib clbi = do
let Just jhcProg = lookupProgram jhcProgram (withPrograms lbi)
let libBi = libBuildInfo lib
let args = constructJHCCmdLine lbi libBi clbi (buildDir lbi) verbosity
let pkgid = display (packageId pkg_descr)
pfile = buildDir lbi </> "jhc-pkg.conf"
hlfile= buildDir lbi </> (pkgid ++ ".hl")
writeFileAtomic pfile . BS.Char8.pack $ jhcPkgConf pkg_descr
rawSystemProgram verbosity jhcProg $
["--build-hl="++pfile, "-o", hlfile] ++
args ++ map display (libModules lib)
buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Executable -> ComponentLocalBuildInfo -> IO ()
buildExe verbosity _pkg_descr lbi exe clbi = do
let Just jhcProg = lookupProgram jhcProgram (withPrograms lbi)
let exeBi = buildInfo exe
let out = buildDir lbi </> exeName exe
let args = constructJHCCmdLine lbi exeBi clbi (buildDir lbi) verbosity
rawSystemProgram verbosity jhcProg (["-o",out] ++ args ++ [modulePath exe])
constructJHCCmdLine :: LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo
-> FilePath -> Verbosity -> [String]
constructJHCCmdLine lbi bi clbi _odir verbosity =
(if verbosity >= deafening then ["-v"] else [])
++ hcOptions JHC bi
++ languageToFlags (compiler lbi) (defaultLanguage bi)
++ extensionsToFlags (compiler lbi) (usedExtensions bi)
++ ["--noauto","-i-"]
++ concat [["-i", l] | l <- nub (hsSourceDirs bi)]
++ ["-i", autogenModulesDir lbi]
++ ["-optc" ++ opt | opt <- PD.ccOptions bi]
++ (concat [ ["-p", display (pkgName pkgid)]
| (_, pkgid) <- componentPackageDeps clbi ])
jhcPkgConf :: PackageDescription -> String
jhcPkgConf pd =
let sline name sel = name ++ ": "++sel pd
lib = fromMaybe (error "no library available") . library
comma = intercalate "," . map display
in unlines [sline "name" (display . pkgName . packageId)
,sline "version" (display . pkgVersion . packageId)
,sline "exposed-modules" (comma . PD.exposedModules . lib)
,sline "hidden-modules" (comma . otherModules . libBuildInfo . lib)
]
installLib :: Verbosity -> FilePath -> FilePath -> PackageDescription -> Library -> IO ()
installLib verb dest build_dir pkg_descr _ = do
let p = display (packageId pkg_descr)++".hl"
createDirectoryIfMissingVerbose verb True dest
installOrdinaryFile verb (build_dir </> p) (dest </> p)
installExe :: Verbosity -> FilePath -> FilePath -> (FilePath,FilePath) -> PackageDescription -> Executable -> IO ()
installExe verb dest build_dir (progprefix,progsuffix) _ exe = do
let exe_name = exeName exe
src = exe_name </> exeExtension
out = (progprefix ++ exe_name ++ progsuffix) </> exeExtension
createDirectoryIfMissingVerbose verb True dest
installExecutableFile verb (build_dir </> src) (dest </> out)