hogre-0.1.1: Setup.hs
import System.IO
import System.Exit
import System.Directory
import System.FilePath
import Control.Applicative
import Control.Monad
import Control.Exception(bracket)
import Data.List
import Distribution.PackageDescription
import Distribution.Simple
import Distribution.Simple.Program
import Distribution.Simple.LocalBuildInfo
import Distribution.Simple.Setup
import Distribution.System
import Distribution.Verbosity
import Distribution.Version
import qualified Distribution.ModuleName
main = defaultMainWithHooks $ simpleUserHooks
{
buildHook = ogreBuildHook
, instHook = ogreInstHook
, cleanHook = ogreCleanHook
, haddockHook = ogreHaddockHook
}
err :: String -> IO a
err str = hPutStrLn stderr str >> exitWith (ExitFailure 1)
getSrcFile :: PackageDescription -> String -> IO FilePath
getSrcFile pd ext = do
let files = filter (\f -> takeExtension f == (extSeparator:ext)) $ extraSrcFiles pd
case files of
[file] -> return file
files -> err $ "Error in extra source files configuration: Exactly one file with the extension \"" ++ ext ++ "\" allowed. Found:\n\t" ++ show files
getProgram :: String -> String -> IO ConfiguredProgram
getProgram src pname = do
mloc <- findProgramLocation normal pname
case mloc of
Nothing -> err $ "Could not find program \"" ++ pname ++ "\".\n" ++
"Try installing the program from " ++ src ++ ".\n" ++
"If you've installed the program, make sure the program is in your PATH."
Just loc -> return $ ConfiguredProgram pname Nothing [] (FoundOnSystem loc)
getFiles :: String -> FilePath -> IO [FilePath]
getFiles ext dir =
map (dir </>) <$> filter (\f -> takeExtension f == (extSeparator:ext)) <$> getDirectoryContents dir
resRoot :: String
resRoot = "res"
resDir :: String -> FilePath
resDir n = resRoot </> n
resCgen = resDir "cgen"
resCgenHsBase = resDir "cgen-hs"
resCgenHs = resCgenHsBase</>"Graphics"</>"Ogre"
resLib = resDir "lib"
graphFile = resDir "graph" </> "graph.txt"
inDir :: FilePath -> IO () -> IO ()
inDir path act = bracket getCwd putCwd (\_ -> setCurrentDirectory path >> act)
where getCwd = getCurrentDirectory
putCwd = setCurrentDirectory
pathToModuleName :: FilePath -> Distribution.ModuleName.ModuleName
pathToModuleName = Distribution.ModuleName.fromString . intercalate "." . splitBy isPathSeparator
where splitBy :: (Char -> Bool) -> String -> [String]
splitBy fun str =
let (w1, rest) = break fun str
in if null rest
then if null w1 then [] else [w1]
else w1 : splitBy fun (tail rest)
fullModuleName :: String -> Distribution.ModuleName.ModuleName
fullModuleName s = Distribution.ModuleName.fromString $ "Graphics.Ogre." ++ s
mkLibrary :: LocalBuildInfo -> IO Library
mkLibrary lb = do
genhsmodulenames <- map takeBaseName <$> getFiles "hs" resCgenHs
cppfiles <- getFiles "cpp" resCgen
includepaths <- getIncludePaths lb
let expModules = map fullModuleName ["HOgre", "Types"]
libbuildinfo = BuildInfo True [] [] [] []
[(Dependency (PackageName "OgreMain")
(laterVersion (Version [1,8] [])))]
[] cppfiles [resCgenHsBase]
(filter (`notElem` expModules)
(map fullModuleName genhsmodulenames))
[] ["OgreMain"] [] includepaths [] [] [] [] [] []
[Dependency (PackageName "base")
(intersectVersionRanges (orLaterVersion (Version [3] []))
(earlierVersion (Version [5] []))),
Dependency (PackageName "haskell98") anyVersion]
return $ Library expModules True libbuildinfo
getConfiguredIncludePaths :: LocalBuildInfo -> [String]
getConfiguredIncludePaths lb =
case library (localPkgDescr lb) of
Nothing -> []
Just l -> includeDirs (libBuildInfo l)
getIncludePaths :: LocalBuildInfo -> IO [String]
getIncludePaths lb = do
let defincludepaths = getConfiguredIncludePaths lb
case buildOS of
Windows -> return defincludepaths
_ -> do
pkgconfig <- getProgram "http://pkg-config.freedesktop.org/" "pkg-config"
mogreincpath <- (filter (\w -> take 2 w == "-I") . words) <$> getProgramOutput normal pkgconfig ["--cflags", "OGRE"]
case mogreincpath of
[] -> do
putStrLn "Warning: Could not find OGRE include path with pkg-config - will assume"
putStrLn " the OGRE headers are in the default include path. If the"
putStrLn " compilation fails, try installing pkg-config and make sure that"
putStrLn " OGRE is installed and pkg-config correctly configured."
putStrLn " Alternatively, use the cabal --extra-include-dirs option."
return defincludepaths
(x:_) -> return $ [drop 2 x]
ogreBuildHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> BuildFlags -> IO ()
ogreBuildHook pd lb uh bf = do
geniffile <- getSrcFile pd "if"
winiffile <- getSrcFile pd "if_win"
igfile <- getSrcFile pd "ig"
hiffile <- getSrcFile pd "hif"
listfile <- getSrcFile pd "list"
winlistfile <- getSrcFile pd "list_win"
cgen <- getProgram "Hackage" "cgen"
grgen <- getProgram "Hackage" "grgen"
cgenhs <- getProgram "Hackage" "cgen-hs"
let headerlistfile = case buildOS of
Windows -> winlistfile
_ -> listfile
let iffile = case buildOS of
Windows -> winiffile
_ -> geniffile
headerlist <- lines <$> readFile headerlistfile
includepaths <- getIncludePaths lb
let includepath = case includepaths of
[] -> ""
(x:_) -> x
when (not $ null includepath) $ putStrLn $ "Searching for OGRE headers in: " ++ includepath
let includesetup = if null includepath then [] else ["--include", includepath]
runProgram normal cgen (["-o", resCgen, "--interface", iffile] ++ includesetup ++ headerlist)
runProgram normal grgen (["--interface", igfile] ++ includesetup ++ ["-o", graphFile] ++ headerlist)
headerfiles <- getFiles "h" resCgen
runProgram normal cgenhs (["--interface", hiffile, "-u", "HOgre.hs", "--hierarchy", "Graphics.Ogre.", "--inherit", graphFile, "-o", resCgenHs] ++ headerfiles)
createDirectoryIfMissing True resLib
lib <- mkLibrary lb
(buildHook simpleUserHooks) pd{library = Just lib} lb uh bf
ogreInstHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
ogreInstHook pd lb uh ifl = do
lib <- mkLibrary lb
(instHook simpleUserHooks) pd{library = Just lib} lb uh ifl
ogreCleanHook pd n uh cf = do
exists <- doesDirectoryExist resRoot
when exists (removeDirectoryRecursive resRoot)
(cleanHook simpleUserHooks) pd n uh cf
ogreHaddockHook pd lb uh hf = do
lib <- mkLibrary lb
(haddockHook simpleUserHooks) pd{library = Just lib} lb uh hf