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
|