forked from depressed-pho/HsOpenSSL
-
Notifications
You must be signed in to change notification settings - Fork 33
/
Setup.hs
executable file
·136 lines (117 loc) · 4.61 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
130
131
132
133
134
135
136
{-# LANGUAGE CPP #-}
{-# LANGUAGE TupleSections #-}
#ifndef MIN_VERSION_Cabal
-- MIN_VERSION_Cabal is defined and available to custom Setup.hs scripts
-- if either GHC >= 8.0 or cabal-install >= 1.24 is used.
-- So if it isn't defined, it's very likely we don't have Cabal >= 2.0.
#define MIN_VERSION_Cabal(x,y,z) 0
#endif
import Distribution.Simple
import Distribution.Simple.Setup (ConfigFlags(..), toFlag)
import Distribution.Simple.LocalBuildInfo (localPkgDescr)
#if MIN_VERSION_Cabal(2,0,0)
import Distribution.PackageDescription (FlagName(..), mkFlagName)
#else
import Distribution.PackageDescription (FlagName(..))
#endif
#if MIN_VERSION_Cabal(2,1,0)
import Distribution.PackageDescription (mkFlagAssignment, unFlagAssignment)
#else
import Distribution.PackageDescription (FlagAssignment)
#endif
import Distribution.Verbosity (silent)
import System.Info (os)
import qualified Control.Exception as E (tryJust, throw)
import System.IO.Error (isUserError)
import Control.Monad (forM)
import Data.List
#if !(MIN_VERSION_Cabal(2,0,0))
mkFlagName = FlagName
#endif
#if !(MIN_VERSION_Cabal(2,1,0))
mkFlagAssignment :: [(FlagName, Bool)] -> FlagAssignment
mkFlagAssignment = id
unFlagAssignment :: FlagAssignment -> [(FlagName, Bool)]
unFlagAssignment = id
#endif
-- On macOS we're checking whether OpenSSL library is avaiable
-- and if not, we're trying to find Homebrew or MacPorts OpenSSL installations.
--
-- Method is dumb -- set homebrew-openssl or macports-openssl flag and try
-- to configure and check C libs.
--
-- If no or multiple libraries are found we display error message
-- with instructions.
main
| os == "darwin" =
defaultMainWithHooks simpleUserHooks { confHook = conf }
| otherwise =
defaultMain
flags = ["homebrew-openssl", "macports-openssl"]
conf descr cfg = do
c <- tryConfig descr cfg
case c of
Right lbi -> return lbi -- library was found
Left e
| unFlagAssignment (configConfigurationsFlags cfg)
`intersect` [(mkFlagName f, True) | f <- flags] /= [] ->
E.throw e
-- flag was set but library still wasn't found
| otherwise -> do
r <- forM flags $ \ f ->
fmap (f,) $ tryConfig descr $
setFlag (mkFlagName f) cfg { configVerbosity = toFlag silent }
-- TODO: configure is a long operation
-- while checkForeignDeps is fast.
-- Perhaps there is a way to configure once
-- and only apply flags to result and check.
-- However, additional `configure`s happen only on macOS
-- and only when library wasn't found.
case [(f,r) | (f, Right r) <- r] of
[(_,lbi)] ->
return lbi -- library was found
[] ->
fail notFound
fs ->
fail $ multipleFound fs
notFound = unlines
[ "Can't find OpenSSL library."
, "Install it via 'brew install openssl' or 'port install openssl'."
, ""
, "If you already have OpenSSL installed, specify the location"
, "of the installed library in cabal.project:"
, ""
, "package HsOpenSSL"
, " extra-include-dirs: ..."
, " extra-lib-dirs: ..."
, ""
, "or use"
, ""
, "cabal configure --extra-include-dirs=... --extra-lib-dirs=..."
]
multipleFound fs = unlines
[ "Multiple OpenSSL libraries were found,"
, "use " ++ intercalate " or " ["'-f " ++ f ++ "'" | (f,_) <- fs]
, "to specify location of installed OpenSSL library."
]
setFlag f c = c { configConfigurationsFlags = mkFlagAssignment
$ go
$ unFlagAssignment
$ configConfigurationsFlags c }
where go [] = []
go (x@(n, _):xs)
| n == f = (f, True) : xs
| otherwise = x : go xs
tryConfig descr flags = do
lbi <- confHook simpleUserHooks descr flags
-- confHook simpleUserHooks == Distribution.Simple.Configure.configure
-- Testing whether C lib and header dependencies are working.
-- We check exceptions only here, to check C libs errors but not other
-- configuration problems like not resolved .cabal dependencies.
E.tryJust ue $ do
postConf simpleUserHooks [] flags (localPkgDescr lbi) lbi
-- postConf simpleUserHooks ~==
-- Distribution.Simple.Configure.checkForeignDeps
return lbi
where ue e | isUserError e = Just e
| otherwise = Nothing