#!/usr/bin/runghc \begin{code} import Control.Monad(when) import Control.Exception(SomeException,try) import System.Directory(removeFile,findExecutable) import System.Exit(ExitCode(ExitSuccess) ,exitWith) import System.IO(hClose, hGetContents, hPutStr, stderr) import System.Process(runInteractiveProcess, waitForProcess) import Distribution.PackageDescription (PackageDescription ,HookedBuildInfo ,emptyHookedBuildInfo ,BuildInfo(extraLibs ,extraLibDirs ,ldOptions ,includeDirs ,ccOptions) ,emptyBuildInfo) import Distribution.PackageDescription.Parse(writeHookedBuildInfo) import Distribution.Simple(UserHooks(preConf,postConf) ,simpleUserHooks ,defaultMainWithHooks) import Distribution.Simple.LocalBuildInfo(LocalBuildInfo) import Distribution.Simple.Setup(ConfigFlags(configVerbosity),Flag) import Distribution.Verbosity(Verbosity) main:: IO () main = defaultMainWithHooks simpleUserHooks{ preConf=preConf , postConf=postConf} where preConf:: [String] -> ConfigFlags -> IO HookedBuildInfo preConf args flags = do try (removeFile "SQLite3.buildinfo"):: IO (Either SomeException ()) return emptyHookedBuildInfo postConf:: [String] -> ConfigFlags -> PackageDescription -> LocalBuildInfo -> IO () postConf args flags _ localbuildinfo = do mb_bi <- pkgConfigBuildInfo (configVerbosity flags) "sqlite3" let bi = case mb_bi of Just bi -> bi Nothing -> emptyBuildInfo{ extraLibs=["sqlite3"] } writeHookedBuildInfo "SQLite3.buildinfo" (Just bi,[]) \end{code} The following code is derived from Distribution.Simple.Configure \begin{code} findProgram:: String -- ^ program name -> Maybe FilePath -- ^ optional explicit path -> IO (Maybe FilePath) findProgram name Nothing = do mb_path <- findExecutable name case mb_path of Nothing -> message ("No " ++ name ++ " found") Just path -> message ("Using " ++ name ++ ": " ++ path) return mb_path findProgram name (Just path) = do message ("Using " ++ name ++ ": " ++ path) return (Just path) -- | rawSystemGrabOutput:: Int -> FilePath -> [String] -> IO String rawSystemGrabOutput verbose path args = do when (verbose > 0) $ putStrLn (path ++ concatMap (' ':) args) (inp,out,err,pid) <- runInteractiveProcess path args Nothing Nothing exitCode <- waitForProcess pid if exitCode /= ExitSuccess then do errMsg <- hGetContents err hPutStr stderr errMsg exitWith exitCode else return () hClose inp hClose err hGetContents out -- | message:: String -> IO () message s = putStrLn $ "configure: " ++ s \end{code} Populate BuildInfo using pkg-config tool. \begin{code} pkgConfigBuildInfo:: Flag Verbosity -> String -> IO (Maybe BuildInfo) pkgConfigBuildInfo verbosity pkgName = do let verbose= -1 mb_pkg_config_path <- findProgram "pkg-config" Nothing case mb_pkg_config_path of Just pkg_config_path -> do message ("configuring "++pkgName++" package using pkg-config") res <- rawSystemGrabOutput verbose pkg_config_path [pkgName, "--libs-only-l"] let libs = map (tail.tail) (words res) res <- rawSystemGrabOutput verbose pkg_config_path [pkgName, "--libs-only-L"] let lib_dirs = map (tail.tail) (words res) res <- rawSystemGrabOutput verbose pkg_config_path [pkgName, "--libs-only-other"] let ld_opts = words res res <- rawSystemGrabOutput verbose pkg_config_path [pkgName, "--cflags-only-I"] let inc_dirs = map (tail.tail) (words res) res <- rawSystemGrabOutput verbose pkg_config_path [pkgName, "--cflags-only-other"] let cc_opts = words res let bi = emptyBuildInfo{ extraLibs=libs , extraLibDirs=lib_dirs , ldOptions=ld_opts , includeDirs=inc_dirs , ccOptions=cc_opts} return (Just bi) Nothing -> do message ("The package will be built using default settings for "++pkgName) return Nothing \end{code}