Future: cabal build-type `Setup` will be phased out in favor of `Hooks`
andreasabel opened this issue · comments
Andreas Abel commented
In the long run, cabal build-type Setup
will be phased out in favor of Hooks
.
The authors of Hooks
(in development) at WellTyped have provided a patch we can use in the future (thanks @alt-romes!):
https://gitlab.haskell.org/mpickering/hooks-setup-testing/-/blob/a664eb3cf456ad8e6e4f922406f1f904575339b5/patches/Agda-2.6.3.patch
diff --git a/Agda.cabal b/Agda.cabal
index 306f81f..5aa17c3 100644
--- a/Agda.cabal
+++ b/Agda.cabal
@@ -1,7 +1,7 @@
name: Agda
version: 2.6.3
cabal-version: 1.24
-build-type: Custom
+build-type: Hooks
license: OtherLicense
license-file: LICENSE
copyright: (c) 2005-2023 The Agda Team.
@@ -172,7 +172,7 @@ flag optimise-heavily
custom-setup
setup-depends: base >= 4.9.0.0 && < 4.18
- , Cabal >= 1.24.0.0 && < 3.9
+ , Cabal >= 1.24.0.0 && < 3.12
, directory >= 1.2.6.2 && < 1.4
, filepath >= 1.4.1.0 && < 1.5
, process >= 1.4.2.0 && < 1.7
diff --git a/Setup.hs b/SetupHooks.hs
similarity index 53%
rename from Setup.hs
rename to SetupHooks.hs
index 3a42cd2..5dd1b3c 100644
--- a/Setup.hs
+++ b/SetupHooks.hs
@@ -1,16 +1,19 @@
-{-# LANGUAGE CPP #-}
{-# LANGUAGE NondecreasingIndentation #-}
+{-# LANGUAGE OverloadedStrings #-}
+
+module SetupHooks ( setupHooks ) where
import Data.Maybe
import Distribution.Simple
import Distribution.Simple.LocalBuildInfo
+import Distribution.Simple.Install (installFileGlob)
import Distribution.Simple.Setup
+import Distribution.Simple.SetupHooks
import Distribution.Simple.BuildPaths (exeExtension)
+import Distribution.Types.TargetInfo (TargetInfo(..))
import Distribution.PackageDescription
-#if MIN_VERSION_Cabal(2,3,0)
import Distribution.System ( buildPlatform )
-#endif
import System.FilePath
import System.Directory (makeAbsolute, removeFile)
import System.Environment (getEnvironment)
@@ -19,58 +22,52 @@ import System.Exit
import System.IO
import System.IO.Error (isDoesNotExistError)
-import Control.Monad (forM_, unless)
+import Control.Monad (when, unless)
import Control.Exception (bracket, catch, throwIO)
-
-main :: IO ()
-main = defaultMainWithHooks userhooks
-
-userhooks :: UserHooks
-userhooks = simpleUserHooks
- { copyHook = copyHook'
- , instHook = instHook'
- }
-
--- Install and copy hooks are default, but amended with .agdai files in data-files.
-instHook' :: PackageDescription -> LocalBuildInfo -> UserHooks -> InstallFlags -> IO ()
-instHook' pd lbi hooks flags = instHook simpleUserHooks pd' lbi hooks flags where
- pd' = pd { dataFiles = concatMap expandAgdaExt $ dataFiles pd }
-
--- Andreas, 2020-04-25, issue #4569: defer 'generateInterface' until after
--- the library has been copied to a destination where it can be found.
--- @cabal build@ will likely no longer produce the .agdai files, but @cabal install@ does.
-copyHook' :: PackageDescription -> LocalBuildInfo -> UserHooks -> CopyFlags -> IO ()
-copyHook' pd lbi hooks flags = do
- -- Copy library and executable etc.
- copyHook simpleUserHooks pd lbi hooks flags
- unless (skipInterfaces lbi) $ do
- -- Generate .agdai files.
- generateInterfaces pd lbi
- -- Copy again, now including the .agdai files.
- copyHook simpleUserHooks pd' lbi hooks flags
- where
- pd' = pd
- { dataFiles = concatMap expandAgdaExt $ dataFiles pd
- -- Andreas, 2020-04-25, issue #4569:
- -- I tried clearing some fields to avoid copying again.
- -- However, cabal does not like me messing with the PackageDescription.
- -- Clearing @library@ or @executables@ leads to internal errors.
- -- Thus, we just copy things again. Not a terrible problem.
- -- , library = Nothing
- -- , executables = []
- -- , subLibraries = []
- -- , foreignLibs = []
- -- , testSuites = []
- -- , benchmarks = []
- -- , extraSrcFiles = []
- -- , extraTmpFiles = []
- -- , extraDocFiles = []
+import Data.Foldable (for_)
+
+setupHooks :: SetupHooks
+setupHooks =
+ noSetupHooks
+ { buildHooks =
+ noBuildHooks
+ { postBuildComponentHook = Just $
+ \ _ lbi tgt ->
+ when ( isMainExecutable tgt ) $
+ unless ( skipInterfaces lbi ) $
+ generateInterfaces lbi
+ }
+ , copyHooks =
+ noCopyHooks
+ { postCopyComponentHook = Just $
+ \ lbi flags tgt ->
+ when ( isMainExecutable tgt ) $
+ unless ( skipInterfaces lbi ) $
+ copyInterfaceFiles lbi flags
+ }
}
--- Used to add .agdai files to data-files
-expandAgdaExt :: FilePath -> [FilePath]
-expandAgdaExt fp | takeExtension fp == ".agda" = [ fp, toIFile fp ]
- | otherwise = [ fp ]
+isMainExecutable :: TargetInfo -> Bool
+isMainExecutable ( TargetInfo { targetComponent = comp } )
+ | CExeName "agda" <- componentName comp
+ = True
+ | otherwise
+ = False
+
+-- | For each ".agda" file in the data files stanza of the package description,
+-- copy the corresponding ".agdai" interface file.
+copyInterfaceFiles :: LocalBuildInfo -> CopyFlags -> IO ()
+copyInterfaceFiles lbi flags = do
+ let pd = localPkgDescr lbi
+ src = dataDir pd
+ dst = datadir $ absoluteInstallDirs pd lbi ( fromFlag $ copyDest flags )
+ for_ ( dataFiles pd ) $ \ fp ->
+ when ( takeExtension fp == ".agda" ) $
+ installFileGlob
+ ( fromFlag $ copyVerbosity flags )
+ ( specVersion pd )
+ ( src, dst )
+ ( toIFile fp )
toIFile :: FilePath -> FilePath
toIFile file = replaceExtension file ".agdai"
@@ -80,15 +77,16 @@ toIFile file = replaceExtension file ".agdai"
skipInterfaces :: LocalBuildInfo -> Bool
skipInterfaces lbi = fromPathTemplate (progSuffix lbi) == "-quicker"
-generateInterfaces :: PackageDescription -> LocalBuildInfo -> IO ()
-generateInterfaces pd lbi = do
+generateInterfaces :: LocalBuildInfo -> IO ()
+generateInterfaces lbi = do
-- for debugging, these are examples how you can inspect the flags...
-- print $ flagAssignment lbi
-- print $ fromPathTemplate $ progSuffix lbi
-- then...
- let bdir = buildDir lbi
+ let pd = localPkgDescr lbi
+ bdir = buildDir lbi
agda = bdir </> "agda" </> "agda" <.> agdaExeExtension
ddir <- makeAbsolute $ "src" </> "data"
@@ -102,7 +100,7 @@ generateInterfaces pd lbi = do
let builtins = filter ((== ".agda") . takeExtension) (dataFiles pd)
-- Remove all existing .agdai files.
- forM_ builtins $ \fp -> do
+ for_ builtins $ \fp -> do
let fullpathi = toIFile (ddir </> fp)
handleExists e | isDoesNotExistError e = return ()
@@ -140,8 +138,4 @@ generateInterfaces pd lbi = do
return ()
agdaExeExtension :: String
-#if MIN_VERSION_Cabal(2,3,0)
agdaExeExtension = exeExtension buildPlatform
-#else
-agdaExeExtension = exeExtension
-#endif