forked from chpatrick/clang-pure
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Setup.hs
129 lines (110 loc) · 4.64 KB
/
Setup.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
{-|
Module : Main
Description : Setup script for clang-pure build
Copyright : (C) Richard Cook, Patrick Chilton 2016
Licence : Apache 2.0
Maintainer : [email protected]
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 #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# 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 Distribution.Simple.Configure
import Distribution.Simple.Utils
import Distribution.Verbosity
import System.Environment
import System.IO.Error
import System.Process
import qualified Data.Version as Version
import Text.ParserCombinators.ReadP
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"
minVersion :: Version.Version
minVersion = Version.makeVersion [ 3, 8, 0 ]
#if !(MIN_VERSION_Cabal(2, 0, 0))
die' :: Verbosity -> String -> IO a
die' _ = die
#endif
findLLVMConfigPaths :: Verbosity -> IO LLVMPathInfo
findLLVMConfigPaths verbosity = do
let llvmConfigCandidates =
"llvm-config" :
[ "llvm-config-" ++ show major ++ "." ++ show minor
| major <- [9,8..3 :: Int]
, minor <- [9,8..0 :: Int]
]
let tryCandidates [] = die' verbosity $ "Could not find llvm-config with minimum version " ++ Version.showVersion minVersion ++ "."
tryCandidates (llvmConfig : candidates) = do
llvmConfigResult <- tryJust
(guard . isDoesNotExistError)
(readProcess llvmConfig ["--version", "--libdir", "--includedir"] "")
case llvmConfigResult of
Left _ -> do
putStrLn ("Could not execute " ++ llvmConfig)
tryCandidates candidates
Right llvmConfigOutput -> do
putStrLn ("Found " ++ llvmConfig)
case lines llvmConfigOutput of
[ versionString, libraryDir, includeDir ] ->
case readP_to_S (Version.parseVersion <* eof) versionString of
[ ( version, _ ) ]
| version >= minVersion -> return $ LLVMPathInfo libraryDir includeDir
| otherwise -> do
putStrLn ("Version too low: " ++ show version)
tryCandidates candidates
_ -> die' verbosity "Couldn't parse llvm-config version string."
_ -> die' verbosity "Unexpected llvm-config output."
tryCandidates llvmConfigCandidates
getLLVMPathInfo :: Verbosity -> IO LLVMPathInfo
getLLVMPathInfo verbosity = do
m'llvmLibDirEnvVar <- lookupEnv llvmLibDirEnvVarName
m'llvmIncludeDirEnvVar <- lookupEnv llvmIncludeDirEnvVarName
case (m'llvmLibDirEnvVar, m'llvmIncludeDirEnvVar) of
( Just libraryDir, Just includeDir ) -> return $ LLVMPathInfo libraryDir includeDir
_ -> findLLVMConfigPaths verbosity
clangPureConfHook :: (GenericPackageDescription, HookedBuildInfo) -> ConfigFlags -> IO LocalBuildInfo
clangPureConfHook (d, bi) flags = do
localBuildInfo <- confHook simpleUserHooks (d, bi) flags
let pd = localPkgDescr localBuildInfo
-- see if it just works (eg on Nix)
mbError <- try $ checkForeignDeps pd localBuildInfo normal
let verbosity = fromFlagOrDefault normal (configVerbosity flags)
addDirs <- case mbError of
Right () -> return id
Left (_ :: SomeException) -> do
warn verbosity "Couldn't find libclang, attempting to find it with llvm-config or environment variables..."
LLVMPathInfo{..} <- getLLVMPathInfo verbosity
return $ \libBuildInfo -> libBuildInfo
{ includeDirs = llvmIncludeDir : includeDirs libBuildInfo
, extraLibDirs = llvmLibraryDir : extraLibDirs libBuildInfo
-- Set the RPATH so the Clang libs can be found later.
, ldOptions = ("-Wl,-rpath," ++ llvmLibraryDir) : ldOptions libBuildInfo
}
let Just lib = library pd
let lbi = libBuildInfo lib
return localBuildInfo
{ localPkgDescr = pd
{ library = Just lib { libBuildInfo = addDirs lbi }
}
}
main :: IO ()
main = defaultMainWithHooks simpleUserHooks { confHook = clangPureConfHook }