{-# LANGUAGE TupleSections #-}
import Control.Exception (IOException, try)
import Data.List (intercalate)
import Data.Maybe (isJust)
import Distribution.Simple
import Distribution.Simple.Setup (ConfigFlags (..), fromFlagOrDefault)
import Distribution.Simple.Utils (die')
import Distribution.Verbosity (Verbosity, normal)
import System.Environment (lookupEnv)
import System.Exit (ExitCode (..))
import System.Process (readProcessWithExitCode)
main :: IO ()
main =
defaultMainWithHooks
simpleUserHooks
{ confHook = \pkg flags -> do
preflightPkgConfig (fromFlagOrDefault normal (configVerbosity flags))
confHook simpleUserHooks pkg flags
}
preflightPkgConfig :: Verbosity -> IO ()
preflightPkgConfig verbosity = do
-- Cabal's pkg-config failure mode can be a bit opaque if you aren't already
-- in the Nix/dev environment. Fail early with a message that points to the
-- common fixes.
-- Only hard-require GTK itself. The standalone executable also uses
-- gtk-layer-shell on Wayland, but we don't want to prevent building the
-- library when that optional dependency is unavailable.
let required = ["gtk+-3.0"]
present <- mapM (\p -> (p,) <$> pkgConfigExists p) required
let missing = [p | (p, ok) <- present, not ok]
if null missing
then pure ()
else do
inDirenv <- isJust <$> lookupEnv "DIRENV_DIR"
let nixHint =
if inDirenv
then "If you just changed Nix inputs, try: `direnv reload`"
else
unwords
[ "If you're using Nix, enter the dev shell:",
"`nix develop` (or `direnv allow` + `direnv reload`)."
]
msg =
unlines
[ "Missing system dependencies required via pkg-config:",
" " ++ intercalate ", " missing,
"",
"This package needs `pkg-config` to find its C dependencies.",
"If you are building the standalone executable for Wayland, you will also need: gtk-layer-shell-0",
"",
nixHint,
"Otherwise, install the development packages for your distro (and pkg-config)."
]
die' verbosity msg
pkgConfigExists :: String -> IO Bool
pkgConfigExists name = do
let cmd = "pkg-config"
args = ["--exists", name]
e <- try (readProcessWithExitCode cmd args "") :: IO (Either IOException (ExitCode, String, String))
pure $ case e of
Right (ExitSuccess, _, _) -> True
_ -> False