{-| Module : Main Description : Setup script for clang-pure build Copyright : (C) Richard Cook, Patrick Chilton 2016 Licence : Apache 2.0 Maintainer : rcook@rcook.org Stability : experimental Portability : portable This setup script adds a configuration hook to the build process to discover the LLVM library and include paths from the standard system-wide installation location or from an alternative location if overridden with both the @CLANG_PURE_LLVM_LIB_DIR@ and @CLANG_PURE_LLVM_INCLUDE_DIR@ environment variables. -} {-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-} {-# OPTIONS_GHC -Wall #-} module Main (main) where import Control.Exception import Control.Monad import Distribution.PackageDescription import Distribution.Simple import Distribution.Simple.LocalBuildInfo import Distribution.Simple.Setup import System.Environment import System.IO.Error import System.Process data SetupException = SetupException String deriving Show instance Exception SetupException data LLVMPathInfo = LLVMPathInfo { llvmLibraryDir :: FilePath , llvmIncludeDir :: FilePath } deriving (Eq, Ord, Show) llvmLibDirEnvVarName :: String llvmLibDirEnvVarName = "CLANG_PURE_LLVM_LIB_DIR" llvmIncludeDirEnvVarName :: String llvmIncludeDirEnvVarName = "CLANG_PURE_LLVM_INCLUDE_DIR" findLLVMConfigPaths :: IO LLVMPathInfo findLLVMConfigPaths = do let llvmConfigCandidates = "llvm-config" : [ "llvm-config-" ++ show major ++ "." ++ show minor | major <- [9,8..3 :: Int] , minor <- [9,8..0 :: Int] ] let tryCandidates [] = throwIO $ SetupException "Could not find llvm-config." tryCandidates (llvmConfig : candidates) = do llvmConfigResult <- tryJust (guard . isDoesNotExistError) (readProcess llvmConfig ["--libdir", "--includedir"] "") case llvmConfigResult of Left _ -> tryCandidates candidates Right llvmConfigOutput -> case lines llvmConfigOutput of [ libraryDir, includeDir ] -> return $ LLVMPathInfo libraryDir includeDir _ -> throwIO $ SetupException "Unexpected llvm-config output." tryCandidates llvmConfigCandidates getLLVMPathInfo :: IO LLVMPathInfo getLLVMPathInfo = do m'llvmLibDirEnvVar <- lookupEnv llvmLibDirEnvVarName m'llvmIncludeDirEnvVar <- lookupEnv llvmIncludeDirEnvVarName case (m'llvmLibDirEnvVar, m'llvmIncludeDirEnvVar) of ( Just libraryDir, Just includeDir ) -> return $ LLVMPathInfo libraryDir includeDir _ -> findLLVMConfigPaths clangPureConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo clangPureConfHook (d, bi) flags = do localBuildInfo <- confHook simpleUserHooks (d, bi) flags let pd = localPkgDescr localBuildInfo let Just lib = library pd let lbi = libBuildInfo lib LLVMPathInfo{..} <- getLLVMPathInfo return localBuildInfo { localPkgDescr = pd { library = Just $ lib { libBuildInfo = lbi { includeDirs = llvmIncludeDir : includeDirs lbi , extraLibDirs = llvmLibraryDir : extraLibDirs lbi , cSources = -- define the generated c-sources here so that they don't get picked up by sdist #ifdef mingw32_HOST_OS ["srcLanguageCClangInternalFFI.c"] -- work around a bug in inline-c (?) #else ["src/Language/C/Clang/Internal/FFI.c"] #endif } } } } main :: IO () main = defaultMainWithHooks simpleUserHooks { confHook = clangPureConfHook }