module Distribution.Simple.UHC (
configure, getInstalledPackages,
buildLib, buildExe, installLib, registerPackage
) where
import Control.Monad
import Data.List
import Distribution.Compat.ReadP
import Distribution.InstalledPackageInfo
import Distribution.Package
import Distribution.PackageDescription
import Distribution.Simple.BuildPaths
import Distribution.Simple.Compiler as C
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.PackageIndex
import Distribution.Simple.Program
import Distribution.Simple.Utils
import Distribution.Text
import Distribution.Verbosity
import Distribution.Version
import Language.Haskell.Extension
import System.Directory
import System.FilePath
import Distribution.System ( Platform )
configure :: Verbosity -> Maybe FilePath -> Maybe FilePath
-> ProgramConfiguration -> IO (Compiler, Maybe Platform, ProgramConfiguration)
configure verbosity hcPath _hcPkgPath conf = do
(_uhcProg, uhcVersion, conf') <-
requireProgramVersion verbosity uhcProgram
(orLaterVersion (Version [1,0,2] []))
(userMaybeSpecifyPath "uhc" hcPath conf)
let comp = Compiler {
compilerId = CompilerId UHC uhcVersion,
compilerLanguages = uhcLanguages,
compilerExtensions = uhcLanguageExtensions
}
compPlatform = Nothing
return (comp, compPlatform, conf')
uhcLanguages :: [(Language, C.Flag)]
uhcLanguages = [(Haskell98, "")]
uhcLanguageExtensions :: [(Extension, C.Flag)]
uhcLanguageExtensions =
let doFlag (f, (enable, disable)) = [(EnableExtension f, enable),
(DisableExtension f, disable)]
alwaysOn = ("", "")
in concatMap doFlag
[(CPP, ("--cpp", "")),
(PolymorphicComponents, alwaysOn),
(ExistentialQuantification, alwaysOn),
(ForeignFunctionInterface, alwaysOn),
(UndecidableInstances, alwaysOn),
(MultiParamTypeClasses, alwaysOn),
(Rank2Types, alwaysOn),
(PatternSignatures, alwaysOn),
(EmptyDataDecls, alwaysOn),
(ImplicitPrelude, ("", "--no-prelude")),
(TypeOperators, alwaysOn),
(OverlappingInstances, alwaysOn),
(FlexibleInstances, alwaysOn)]
getInstalledPackages :: Verbosity -> Compiler -> PackageDBStack -> ProgramConfiguration
-> IO PackageIndex
getInstalledPackages verbosity comp packagedbs conf = do
let compilerid = compilerId comp
systemPkgDir <- rawSystemProgramStdoutConf verbosity uhcProgram conf ["--meta-pkgdir-system"]
userPkgDir <- getUserPackageDir
let pkgDirs = nub (concatMap (packageDbPaths userPkgDir systemPkgDir) packagedbs)
pkgs <- liftM (map addBuiltinVersions . concat) .
mapM (\ d -> getDirectoryContents d >>= filterM (isPkgDir (display compilerid) d)) .
concatMap lines $ pkgDirs
let iPkgs =
map mkInstalledPackageInfo $
concatMap parsePackage $
pkgs
return (fromList iPkgs)
getUserPackageDir :: IO FilePath
getUserPackageDir =
do
homeDir <- getHomeDirectory
return $ homeDir </> ".cabal" </> "lib"
packageDbPaths :: FilePath -> FilePath -> PackageDB -> [FilePath]
packageDbPaths user system db =
case db of
GlobalPackageDB -> [ system ]
UserPackageDB -> [ user ]
SpecificPackageDB path -> [ path ]
addBuiltinVersions :: String -> String
addBuiltinVersions xs = xs
installedPkgConfig :: String
installedPkgConfig = "installed-pkg-config"
isPkgDir :: String -> String -> String -> IO Bool
isPkgDir _ _ ('.' : _) = return False
isPkgDir c dir xs = do
let candidate = dir </> uhcPackageDir xs c
doesFileExist (candidate </> installedPkgConfig)
parsePackage :: String -> [PackageId]
parsePackage x = map fst (filter (\ (_,y) -> null y) (readP_to_S parse x))
mkInstalledPackageInfo :: PackageId -> InstalledPackageInfo
mkInstalledPackageInfo p = emptyInstalledPackageInfo
{ installedPackageId = InstalledPackageId (display p),
sourcePackageId = p }
buildLib :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Library -> ComponentLocalBuildInfo -> IO ()
buildLib verbosity pkg_descr lbi lib clbi = do
systemPkgDir <- rawSystemProgramStdoutConf verbosity uhcProgram (withPrograms lbi) ["--meta-pkgdir-system"]
userPkgDir <- getUserPackageDir
let runUhcProg = rawSystemProgramConf verbosity uhcProgram (withPrograms lbi)
let uhcArgs =
["--pkg-build=" ++ display (packageId pkg_descr)]
++ constructUHCCmdLine userPkgDir systemPkgDir
lbi (libBuildInfo lib) clbi
(buildDir lbi) verbosity
++ map (map (\ c -> if c == '.' then pathSeparator else c))
(map display (libModules lib))
runUhcProg uhcArgs
return ()
buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Executable -> ComponentLocalBuildInfo -> IO ()
buildExe verbosity _pkg_descr lbi exe clbi = do
systemPkgDir <- rawSystemProgramStdoutConf verbosity uhcProgram (withPrograms lbi) ["--meta-pkgdir-system"]
userPkgDir <- getUserPackageDir
let runUhcProg = rawSystemProgramConf verbosity uhcProgram (withPrograms lbi)
let uhcArgs =
constructUHCCmdLine userPkgDir systemPkgDir
lbi (buildInfo exe) clbi
(buildDir lbi) verbosity
++ ["--output", buildDir lbi </> exeName exe]
++ [modulePath exe]
runUhcProg uhcArgs
constructUHCCmdLine :: FilePath -> FilePath
-> LocalBuildInfo -> BuildInfo -> ComponentLocalBuildInfo
-> FilePath -> Verbosity -> [String]
constructUHCCmdLine user system lbi bi clbi odir verbosity =
(if verbosity >= deafening then ["-v4"]
else if verbosity >= normal then []
else ["-v0"])
++ hcOptions UHC bi
++ languageToFlags (compiler lbi) (defaultLanguage bi)
++ extensionsToFlags (compiler lbi) (usedExtensions bi)
++ ["--hide-all-packages"]
++ uhcPackageDbOptions user system (withPackageDB lbi)
++ ["--package=uhcbase"]
++ ["--package=" ++ display (pkgName pkgid) | (_, pkgid) <- componentPackageDeps clbi ]
++ ["-i" ++ odir]
++ ["-i" ++ l | l <- nub (hsSourceDirs bi)]
++ ["-i" ++ autogenModulesDir lbi]
++ ["--odir=" ++ odir]
++ (case withOptimization lbi of
NoOptimisation -> ["-O0"]
NormalOptimisation -> ["-O1"]
MaximumOptimisation -> ["-O2"])
uhcPackageDbOptions :: FilePath -> FilePath -> PackageDBStack -> [String]
uhcPackageDbOptions user system db = map (\ x -> "--pkg-searchpath=" ++ x)
(concatMap (packageDbPaths user system) db)
installLib :: Verbosity -> LocalBuildInfo
-> FilePath -> FilePath -> FilePath
-> PackageDescription -> Library -> IO ()
installLib verbosity _lbi targetDir _dynlibTargetDir builtDir pkg _library = do
installDirectoryContents verbosity (builtDir </> display (packageId pkg)) targetDir
uhcTarget, uhcTargetVariant :: String
uhcTarget = "bc"
uhcTargetVariant = "plain"
uhcPackageDir :: String -> String -> FilePath
uhcPackageSubDir :: String -> FilePath
uhcPackageDir pkgid compilerid = pkgid </> uhcPackageSubDir compilerid
uhcPackageSubDir compilerid = compilerid </> uhcTarget </> uhcTargetVariant
registerPackage
:: Verbosity
-> InstalledPackageInfo
-> PackageDescription
-> LocalBuildInfo
-> Bool
-> PackageDBStack
-> IO ()
registerPackage verbosity installedPkgInfo pkg lbi inplace _packageDbs = do
let installDirs = absoluteInstallDirs pkg lbi NoCopyDest
pkgdir | inplace = buildDir lbi </> uhcPackageDir (display pkgid) (display compilerid)
| otherwise = libdir installDirs </> uhcPackageSubDir (display compilerid)
createDirectoryIfMissingVerbose verbosity True pkgdir
writeUTF8File (pkgdir </> installedPkgConfig)
(showInstalledPackageInfo installedPkgInfo)
where
pkgid = packageId pkg
compilerid = compilerId (compiler lbi)