----------------------------------------------------------------------------- -- | -- Module : Distribution.Simple.JHC -- Copyright : Isaac Jones 2003-2006 -- License : BSD3 -- -- Maintainer : cabal-devel@haskell.org -- Portability : portable -- -- This module contains most of the JHC-specific code for configuring, building -- and installing packages. 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 -- ----------------------------------------------------------------------------- -- Configuring 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, "")] -- | The flags for the supported extensions jhcLanguageExtensions :: [(Extension, Flag)] jhcLanguageExtensions = [(EnableExtension TypeSynonymInstances , "") ,(DisableExtension TypeSynonymInstances , "") ,(EnableExtension ForeignFunctionInterface , "") ,(DisableExtension ForeignFunctionInterface , "") ,(EnableExtension ImplicitPrelude , "") -- Wrong ,(DisableExtension ImplicitPrelude , "--noprelude") ,(EnableExtension CPP , "-fcpp") ,(DisableExtension CPP , "-fno-cpp") ] getInstalledPackages :: Verbosity -> PackageDBStack -> ProgramConfiguration -> IO InstalledPackageIndex getInstalledPackages verbosity _packageDBs conf = do -- jhc --list-libraries lists all available libraries. -- How shall I find out, whether they are global or local -- without checking all files and locations? 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 -- ----------------------------------------------------------------------------- -- Building -- | Building a package for JHC. -- Currently C source files are not supported. 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) -- | Building an executable for JHC. -- Currently C source files are not supported. 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] -- It would be better if JHC would accept package names with versions, -- but JHC-0.7.2 doesn't accept this. -- Thus, we have to strip the version with 'pkgName'. ++ (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)