{-# LANGUAGE CPP #-} {-# LANGUAGE TupleSections #-} import Distribution.Simple import Distribution.Simple.Setup (ConfigFlags(..), toFlag) import Distribution.Simple.LocalBuildInfo (localPkgDescr) #if __GLASGOW_HASKELL__ >= 802 import Distribution.PackageDescription (FlagName(..), mkFlagName) #else import Distribution.PackageDescription (FlagName(..)) #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 -- 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 | 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'" , "or use --extra-include-dirs= and --extra-lib-dirs=" , "to specify location of installed OpenSSL library." ] 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 = go (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 #if __GLASGOW_HASKELL__ < 802 mkFlagName = FlagName #endif