module Distribution.Simple.NHC
( configure
, buildLib, buildExe
, installLib, installExe
) where
import Distribution.Package
( PackageIdentifier, packageName, Package(..) )
import Distribution.PackageDescription
( PackageDescription(..), BuildInfo(..), Library(..), Executable(..)
, hcOptions )
import Distribution.ModuleName (ModuleName)
import qualified Distribution.ModuleName as ModuleName
import Distribution.Simple.LocalBuildInfo
( LocalBuildInfo(..), ComponentLocalBuildInfo(..) )
import Distribution.Simple.BuildPaths
( mkLibName, objExtension, exeExtension )
import Distribution.Simple.Compiler
( CompilerFlavor(..), CompilerId(..), Compiler(..)
, Flag, extensionsToFlags )
import Language.Haskell.Extension
( Extension(..) )
import Distribution.Simple.Program
( ProgramConfiguration, userMaybeSpecifyPath, programPath
, requireProgram, requireProgramVersion, lookupProgram
, nhcProgram, hmakeProgram, ldProgram, arProgram
, rawSystemProgramConf )
import Distribution.Simple.Utils
( die, info, findFileWithExtension, findModuleFiles
, installOrdinaryFile, installExecutableFile, installOrdinaryFiles
, createDirectoryIfMissingVerbose )
import Distribution.Version
( Version(..), orLaterVersion )
import Distribution.Verbosity
import Distribution.Text
( display )
import System.FilePath
( (</>), (<.>), normalise, takeDirectory, dropExtension )
import System.Directory
( removeFile )
import Data.List ( nub )
import Control.Monad ( when, unless )
import Distribution.Compat.Exception
configure :: Verbosity -> Maybe FilePath -> Maybe FilePath
-> ProgramConfiguration -> IO (Compiler, ProgramConfiguration)
configure verbosity hcPath _hcPkgPath conf = do
(_nhcProg, nhcVersion, conf') <-
requireProgramVersion verbosity nhcProgram
(orLaterVersion (Version [1,20] []))
(userMaybeSpecifyPath "nhc98" hcPath conf)
(_hmakeProg, _hmakeVersion, conf'') <-
requireProgramVersion verbosity hmakeProgram
(orLaterVersion (Version [3,13] [])) conf'
(_ldProg, conf''') <- requireProgram verbosity ldProgram conf''
(_arProg, conf'''') <- requireProgram verbosity arProgram conf'''
let comp = Compiler {
compilerId = CompilerId NHC nhcVersion,
compilerExtensions = nhcLanguageExtensions
}
return (comp, conf'''')
nhcLanguageExtensions :: [(Extension, Flag)]
nhcLanguageExtensions =
[(NoMonomorphismRestriction, "")
,(ForeignFunctionInterface, "")
,(ExistentialQuantification, "")
,(EmptyDataDecls, "")
,(NamedFieldPuns, "-puns")
,(CPP, "-cpp")
]
buildLib :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Library -> ComponentLocalBuildInfo -> IO ()
buildLib verbosity pkg_descr lbi lib clbi = do
let conf = withPrograms lbi
Just nhcProg = lookupProgram nhcProgram conf
let bi = libBuildInfo lib
modules = exposedModules lib ++ otherModules bi
extensionFlags = extensionsToFlags (compiler lbi) (extensions bi)
inFiles <- getModulePaths lbi bi modules
let targetDir = buildDir lbi
srcDirs = nub (map takeDirectory inFiles)
destDirs = map (targetDir </>) srcDirs
mapM_ (createDirectoryIfMissingVerbose verbosity True) destDirs
rawSystemProgramConf verbosity hmakeProgram conf $
["-hc=" ++ programPath nhcProg]
++ nhcVerbosityOptions verbosity
++ ["-d", targetDir, "-hidir", targetDir]
++ extensionFlags
++ maybe [] (hcOptions NHC . libBuildInfo)
(library pkg_descr)
++ concat [ ["-package", display (packageName pkgid) ]
| (_, pkgid) <- componentPackageDeps clbi ]
++ inFiles
info verbosity "Linking..."
let
libFilePath = targetDir </> mkLibName (packageId pkg_descr)
hObjs = [ targetDir </> ModuleName.toFilePath m <.> objExtension
| m <- modules ]
unless (null hObjs ) $ do
removeFile libFilePath `catchIO` \_ -> return ()
let arVerbosity | verbosity >= deafening = "v"
| verbosity >= normal = ""
| otherwise = "c"
rawSystemProgramConf verbosity arProgram (withPrograms lbi) $
["q"++ arVerbosity, libFilePath]
++ hObjs
buildExe :: Verbosity -> PackageDescription -> LocalBuildInfo
-> Executable -> ComponentLocalBuildInfo -> IO ()
buildExe verbosity pkg_descr lbi exe clbi = do
let conf = withPrograms lbi
Just nhcProg = lookupProgram nhcProgram conf
when (dropExtension (modulePath exe) /= exeName exe) $
die $ "hmake does not support exe names that do not match the name of "
++ "the 'main-is' file. You will have to rename your executable to "
++ show (dropExtension (modulePath exe))
let bi = buildInfo exe
modules = otherModules bi
extensionFlags = extensionsToFlags (compiler lbi) (extensions bi)
inFiles <- getModulePaths lbi bi modules
let targetDir = buildDir lbi </> exeName exe
exeDir = targetDir </> (exeName exe ++ "-tmp")
srcDirs = nub (map takeDirectory (modulePath exe : inFiles))
destDirs = map (exeDir </>) srcDirs
mapM_ (createDirectoryIfMissingVerbose verbosity True) destDirs
rawSystemProgramConf verbosity hmakeProgram conf $
["-hc=" ++ programPath nhcProg]
++ nhcVerbosityOptions verbosity
++ ["-d", targetDir, "-hidir", targetDir]
++ extensionFlags
++ maybe [] (hcOptions NHC . libBuildInfo)
(library pkg_descr)
++ concat [ ["-package", display (packageName pkgid) ]
| (_, pkgid) <- componentPackageDeps clbi ]
++ inFiles
++ [exeName exe]
nhcVerbosityOptions :: Verbosity -> [String]
nhcVerbosityOptions verbosity
| verbosity >= deafening = ["-v"]
| verbosity >= normal = []
| otherwise = ["-q"]
getModulePaths :: LocalBuildInfo -> BuildInfo -> [ModuleName] -> IO [FilePath]
getModulePaths lbi bi modules = sequence
[ findFileWithExtension ["hs", "lhs"] (buildDir lbi : hsSourceDirs bi)
(ModuleName.toFilePath module_) >>= maybe (notFound module_) (return . normalise)
| module_ <- modules ]
where notFound module_ = die $ "can't find source for module " ++ display module_
installExe :: Verbosity
-> FilePath
-> FilePath
-> (FilePath, FilePath)
-> Executable
-> IO ()
installExe verbosity pref buildPref (progprefix,progsuffix) exe
= do createDirectoryIfMissingVerbose verbosity True pref
let exeBaseName = exeName exe
exeFileName = exeBaseName <.> exeExtension
fixedExeFileName = (progprefix ++ exeBaseName ++ progsuffix) <.> exeExtension
installExecutableFile verbosity
(buildPref </> exeBaseName </> exeFileName)
(pref </> fixedExeFileName)
installLib :: Verbosity
-> FilePath
-> FilePath
-> PackageIdentifier
-> Library
-> IO ()
installLib verbosity pref buildPref pkgid lib
= do let bi = libBuildInfo lib
modules = exposedModules lib ++ otherModules bi
findModuleFiles [buildPref] ["hi"] modules
>>= installOrdinaryFiles verbosity pref
let libName = mkLibName pkgid
installOrdinaryFile verbosity (buildPref </> libName) (pref </> libName)