Skip to content

Prepare Stack for Cabal's changing approach to hooks #6542

Closed

Description

@mpilgrem

Motivation:

The Hooks build type was introduced in Cabal 3.14. GHC 9.12.1 comes with Cabal-3.14.1.0.

Currently:

  • Stack itself has build type Custom, which makes use of generateBuildModule; and
  • Stack uses replHook in StackSetupShim.hs to cause Cabal to create the autogenerated files for every configured component, without building everything, before Stack uses ghc --interactive.

Related question: haskellfoundation/tech-proposals#60 (comment)

Activity

  1. mpilgrem commented on Mar 31, 2024

    @mpilgrem
    MemberAuthor

    Currently:

    Stack has:

    stackReplHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> ReplFlags -> [String] -> IO ()
    stackReplHook pkg_descr lbi hooks flags args = do
        let distPref = fromFlag (replDistPref flags)
            verbosity = fromFlag (replVerbosity flags)
        case args of
            ("stack-initial-build-steps":rest)
                | null rest -> initialBuildSteps distPref pkg_descr lbi verbosity
                | otherwise ->
                    fail "Misuse of running Setup.hs with stack-initial-build-steps, expected no arguments"
            _ -> replHook simpleUserHooks pkg_descr lbi hooks flags args

    Cabal-3.10.3.0 has:

    -- | Runs 'componentInitialBuildSteps' on every configured component.
    initialBuildSteps ::
         FilePath -- ^"dist" prefix
      -> PackageDescription  -- ^mostly information from the .cabal file
      -> LocalBuildInfo -- ^Configuration information
      -> Verbosity -- ^The verbosity to use
      -> IO ()
    initialBuildSteps distPref pkg_descr lbi verbosity =
      withAllComponentsInBuildOrder pkg_descr lbi $ \_comp clbi ->
        componentInitialBuildSteps distPref pkg_descr lbi clbi verbosity
    
    -- | Creates the autogenerated files for a particular configured component.
    componentInitialBuildSteps :: 
         FilePath -- ^"dist" prefix
      -> PackageDescription  -- ^mostly information from the .cabal file
      -> LocalBuildInfo -- ^Configuration information
      -> ComponentLocalBuildInfo
      -> Verbosity -- ^The verbosity to use
      -> IO ()
    componentInitialBuildSteps _distPref pkg_descr lbi clbi verbosity = do
      createDirectoryIfMissingVerbose verbosity True (componentBuildDir lbi clbi)
      writeAutogenFiles verbosity pkg_descr lbi clbi
    
    -- Field of UserHooks
    replHook :: PackageDescription -> LocalBuildInfo -> UserHooks -> ReplFlags -> [String] -> IO ()

    and, for stack --verbose ghci for a simple one-package project boo (extract, reformatted):

    [info] boo> configure (lib + exe)
    [debug] Run process within ...\boo\:
    C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_9p6GVs8J_3.10.1.0_ghc-9.6.4.exe 
    --verbose=1 
    --builddir=.stack-work\dist\ab060f89
    configure 
    --with-ghc=...\x86_64-windows\ghc-9.6.4\bin\ghc-9.6.4.exe 
    --with-ghc-pkg=...\x86_64-windows\ghc-9.6.4\bin\ghc-pkg-9.6.4.exe
    --user 
    --package-db=clear 
    --package-db=global 
    --package-db=C:\sr\snapshots\d672ac94\pkgdb 
    --package-db=...\boo\.stack-work\install\fd78de5f\pkgdb 
    --libdir=...\boo\.stack-work\install\fd78de5f\lib 
    --bindir=...\boo\.stack-work\install\fd78de5f\bin 
    --datadir=...\boo\.stack-work\install\fd78de5f\share 
    --libexecdir=...\boo\.stack-work\install\fd78de5f\libexec 
    --sysconfdir=...\boo\.stack-work\install\fd78de5f\etc 
    --docdir=...\boo\.stack-work\install\fd78de5f\doc\boo-0.1.0.0 
    --htmldir=...\boo\.stack-work\install\fd78de5f\doc\boo-0.1.0.0 
    --haddockdir=...\boo\.stack-work\install\fd78de5f\doc\boo-0.1.0.0 
    --dependency=base=base-4.18.2.0 
    --ghc-options -haddock 
    --extra-include-dirs=...\x86_64-windows\msys2-20230526\mingw64\include 
    --extra-lib-dirs=...\x86_64-windows\msys2-20230526\mingw64\lib 
    --extra-lib-dirs=...\x86_64-windows\msys2-20230526\mingw64\bin 
    --exact-configuration 
    --ghc-option=-fhide-source-paths
    ...
    [info] boo> initial-build-steps (lib + exe)
    [debug] Run process within ...\boo\: 
    C:\sr\setup-exe-cache\x86_64-windows\Cabal-simple_9p6GVs8J_3.10.1.0_ghc-9.6.4.exe 
    --verbose=1 
    --builddir=.stack-work\dist\ab060f89 
    repl 
    stack-initial-build-steps <<<< This is what triggers the use of `initialBuildSteps`
    
  2. mpilgrem commented on Mar 31, 2024

    @mpilgrem
    MemberAuthor

    An alternative to the replHook 'trick' would be for the 'setup' executable to get the information that initialBuildSteps needs. Proof of concept:

    module Main (main) where
    
    import Data.List ( stripPrefix )
    import Distribution.Parsec ( eitherParsec )
    import Distribution.Simple.Build ( initialBuildSteps )
    import Distribution.Simple.Configure ( getPersistBuildConfig )
    import Distribution.Simple.PackageDescription ( readGenericPackageDescription )
    import Distribution.Simple.Utils ( findPackageDesc )
    import Distribution.Types.GenericPackageDescription
             ( GenericPackageDescription (..) )
    import System.Environment ( getArgs )
    
    main :: IO ()
    main = do
      args <- getArgs
      case args of
        [] -> putStrLn "Expected Cabal verbosity as first argument and builddir \
                        \as second argument."
        arg1:arg2:[] -> do
          eFp <- findPackageDesc ""
          case eFp of
            Left msg1 -> putStrLn msg1
            Right fp -> do
              let mRawVerbosity = stripPrefix "--verbose=" arg1
                  mRawBuildDir = stripPrefix "--builddir=" arg2
              case (mRawVerbosity, mRawBuildDir) of
                (Nothing, _) ->
                  putStrLn "Expected first argument to start --verbose="
                (_, Nothing) ->
                  putStrLn "Expected second argument to start --builddir="
                (Just rawVerbosity, Just rawBuildDir) -> do
                  case eitherParsec rawVerbosity of
                    Left msg2 -> putStrLn msg2
                    Right verbosity -> do
                      gpd <- readGenericPackageDescription verbosity fp
                      let pd = packageDescription gpd
                      lbi <- getPersistBuildConfig rawBuildDir
                      initialBuildSteps rawBuildDir pd lbi verbosity
        _ -> putStrLn "Expected only Cabal verbosity as first argument and \
                      \builddir as second argument."
  3. added 7 commits that reference this issue on Apr 1, 2024
  4. self-assigned this
    on Apr 1, 2024
  5. sheaf commented on Apr 3, 2024

    @sheaf

    I believe this is incorrect for a package with Custom build-type in which the custom Setup creates autogenerated modules. Is there a reason you cannot call Setup repl here?

  6. added a commit that references this issue on Apr 19, 2024
  7. added a commit that references this issue on Apr 27, 2024
  8. 6 remaining items

  9. added 4 commits that reference this issue on Oct 20, 2026
  10. mpilgrem commented on Oct 21, 2026

    @mpilgrem
    MemberAuthor

    @ulysses4ever, the master branch version of Stack now supports the Hooks build type.

  11. ulysses4ever commented on Oct 21, 2026

    @ulysses4ever

    Thanks a lot @mpilgrem! Impressive turnaround time, truly. Looking forward for a release.

  12. added a commit that references this issue on Oct 21, 2026
    8f1b86f
  13. sheaf commented on Oct 22, 2026

    @sheaf

    Great work @mpilgrem, that's fantastic.

    About your previous question re: Cabal-hooks not being a boot package. I thought about this and I think it is all working as designed. You are allowed to depend on whatever package you want in the setup-depends of a build-type: Hooks package; for example the package author may have added build-type: lens. So I think Cabal-hooks not being a boot package should not pose any particular difficulty here. Does that line up with your experience when adding the support for build-type: Hooks in stack?

    I'd love to know anything else you thought was poorly documented so that we can improve the docs.

  14. mpilgrem commented on Oct 22, 2026

    @mpilgrem
    MemberAuthor

    @sheaf, as Cabal-hooks is not a GHC boot package, it will not be included in Stackage snapshot's 'automatically'. It would be a Good Thing if Cabal-hooks could participate in Stackage snapshots (the currently relevant one being nightly-2026-10-22 for GHC 9.12.4/Cabal-3.14.2.0).

  15. chreekat commented on Oct 23, 2026

    @chreekat
    Member

    Ooh yes, that seems like a great idea. You can find instructions at https://github.com/commercialhaskell/stackage/#add-your-package

  16. mpilgrem commented on Oct 23, 2026

    @mpilgrem
    MemberAuthor

    Pinging @Mikolaj on the topic of Cabal-hooks and Stackage, as I see cabal-install and cabal-install-solver from the same GitHub repository are listed under his name on Stackage.

  17. Mikolaj commented on Oct 23, 2026

    @Mikolaj

    Yes, that makes sense. I currently see only two cabal packages on Stackage:

        - cabal-install
        - cabal-install-solver
    

    Which of the six we publish to Hackage shall I add: Cabal-syntax Cabal Cabal-hooks hooks-exe cabal-install cabal-install-solver?

  18. mpilgrem commented on Oct 23, 2026

    @mpilgrem
    MemberAuthor

    @Mikolaj, you should not add to a Stackage snapshot any packages that are GHC boot packages (eg Cabal, Cabal-syntax), they come in indirectly by the snapshot specifying a version of GHC (and it causes trouble if they also come in directly). Any other packages published on Hackage can be added directly.

  19. added a commit that references this issue on Oct 31, 2026
    502b54f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions