packages feed

termonad-1.0.1.0: Setup.hs

-- This file comes from cabal-doctest:
-- https://github.com/phadej/cabal-doctest/blob/master/simple-example
--
-- It is needed so that doctest can be run with the same options as the modules
-- are compiled with.

{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedLists #-}
{-# OPTIONS_GHC -Wall #-}
module Main (main) where

import Data.Maybe (catMaybes)
import Data.Monoid ((<>))
import Data.Version (Version)
import Distribution.PackageDescription (HookedBuildInfo, cppOptions, emptyBuildInfo)
import Distribution.Simple (UserHooks, defaultMainWithHooks, preBuild, preRepl, simpleUserHooks)
import Distribution.Simple.Program (configureProgram, defaultProgramConfiguration, getDbProgramOutput, pkgConfigProgram)
import Distribution.Text (simpleParse)
import Distribution.Verbosity (normal)

#ifndef MIN_VERSION_cabal_doctest
#define MIN_VERSION_cabal_doctest(x,y,z) 0
#endif

#if MIN_VERSION_cabal_doctest(1,0,0)

import Distribution.Extra.Doctest (addDoctestsUserHook)
main :: IO ()
main = do
  cppOpts <- getTermonadCPPOpts
  defaultMainWithHooks . addPkgConfigTermonadUserHook cppOpts $
    addDoctestsUserHook "doctests" simpleUserHooks

#else

#ifdef MIN_VERSION_Cabal
-- If the macro is defined, we have new cabal-install,
-- but for some reason we don't have cabal-doctest in package-db
--
-- Probably we are running cabal sdist, when otherwise using new-build
-- workflow
#warning You are configuring this package without cabal-doctest installed. \
         The doctests test-suite will not work as a result. \
         To fix this, install cabal-doctest before configuring.
#endif

main :: IO ()
main = do
  cppOpts <- getTermonadCPPOpts
  defaultMainWithHooks $ addPkgConfigTermonadUserHook cppOpts simpleUserHooks

#endif

-- | Add CPP macros representing the version of the GTK and VTE system
-- libraries.
addPkgConfigTermonadUserHook :: [String] -> UserHooks -> UserHooks
addPkgConfigTermonadUserHook cppOpts oldUserHooks = do
  oldUserHooks
    { preBuild = pkgConfigTermonadHook cppOpts $ preBuild oldUserHooks
    , preRepl = pkgConfigTermonadHook cppOpts (preRepl oldUserHooks)
    }

pkgConfigTermonadHook :: [String] -> (args -> flags -> IO HookedBuildInfo) -> args -> flags -> IO HookedBuildInfo
pkgConfigTermonadHook cppOpts oldFunc args flags = do
  (maybeOldLibHookedInfo, oldExesHookedInfo) <- oldFunc args flags
  case maybeOldLibHookedInfo of
    Just oldLibHookedInfo -> do
      let newLibHookedInfo =
            oldLibHookedInfo
              { cppOptions = cppOptions oldLibHookedInfo <> cppOpts
              }
      pure (Just newLibHookedInfo, oldExesHookedInfo)
    Nothing -> do
      let newLibHookedInfo =
            emptyBuildInfo
              { cppOptions = cppOpts
              }
      pure (Just newLibHookedInfo, oldExesHookedInfo)

getTermonadCPPOpts :: IO [String]
getTermonadCPPOpts = do
  gtk <- getGtkVersionCPPOpts
  vte <- getVteVersionCPPOpts
  pure $ gtk <> vte

getVteVersionCPPOpts :: IO [String]
getVteVersionCPPOpts = do
  maybeVers <- getPkgConfigVersionFor "vte-2.91"
  case maybeVers of
    Nothing -> pure []
    Just vers -> pure $ createVteVersionCPPOpts vers

getGtkVersionCPPOpts :: IO [String]
getGtkVersionCPPOpts = do
  maybeVers <- getPkgConfigVersionFor "gtk+-3.0"
  case maybeVers of
    Nothing -> pure []
    Just vers -> pure $ createGtkVersionCPPOpts vers

-- | Just like 'createGtkVersionCPPOpts' but for VTE instead of GTK.
createVteVersionCPPOpts
  :: Version
  -> [String]
createVteVersionCPPOpts vers =
  catMaybes $
    [ if vers >= [0,44] then Just "-DVTE_VERSION_GEQ_0_44" else Nothing
    ]

-- | Based on the version of the GTK3 library as reported by @pkg-config@, return
-- a list of CPP macros that contain the GTK version.  These can be used in the
-- Haskell code to work around differences in the gi-gtk library Haskell
-- library when compiled against different versions of the GTK system library.
--
-- This list may need to be added to.
createGtkVersionCPPOpts
  :: Version  -- ^ 'Version' of the GTK3 library as reported by @pkg-config@.
  -> [String] -- ^ A list of CPP macros to show the GTK version.
createGtkVersionCPPOpts gtkVersion =
  catMaybes $
    [ if gtkVersion >= [3,22] then Just "-DGTK_VERSION_GEQ_3_22" else Nothing
    ]

getPkgConfigVersionFor :: String -> IO (Maybe Version)
getPkgConfigVersionFor program = do
  pkgDb <- configureProgram normal pkgConfigProgram defaultProgramConfiguration
  pkgConfigOutput <-
    getDbProgramOutput normal pkgConfigProgram pkgDb ["--modversion", program]
  -- Drop the newline on the end of the pkgConfigOutput.
  -- This should give us a version number like @3.22.11@.
  let rawProgramVersion = reverse $ drop 1 $ reverse pkgConfigOutput
  let maybeProgramVersion = simpleParse rawProgramVersion
  case maybeProgramVersion of
    Nothing -> do
      putStrLn $
        "In Setup.hs, in getPkgConfigVersionFor, could not parse " <>
        program <> " version: " <> show pkgConfigOutput
      putStrLn $
        "\nNot defining any CPP macros based on the version of the system " <>
        program <> " library."
      putStrLn "\nCompilation of termonad may fail."
      pure Nothing
    Just programVersion -> pure $ Just programVersion