Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions cabal-install/src/Distribution/Client/Dependency.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
-----------------------------------------------------------------------------
{-# LANGUAGE LambdaCase #-}

-----------------------------------------------------------------------------

Expand Down Expand Up @@ -637,26 +638,52 @@ addDefaultSetupDependencies defaultSetupDeps params =
{ PD.packageDescription =
pkgdesc
{ PD.setupBuildInfo =
case PD.setupBuildInfo pkgdesc of
Just sbi -> Just sbi
Nothing -> case defaultSetupDeps srcpkg of
Nothing -> Nothing
Just deps
| isCustom ->
Just
PD.SetupBuildInfo
{ PD.defaultSetupDepends = True
, PD.setupDepends = deps
}
| otherwise -> Nothing
applyDefaultSetupBuildInfo
(PD.setupBuildInfo pkgdesc)
}
}
}
where
isCustom = PD.buildType pkgdesc == PD.Custom || PD.buildType pkgdesc == PD.Hooks
mbSetupDeps = defaultSetupDeps srcpkg
gpkgdesc = srcpkgDescription srcpkg
pkgdesc = PD.packageDescription gpkgdesc

applyDefaultSetupBuildInfo :: Maybe PD.SetupBuildInfo -> Maybe PD.SetupBuildInfo
applyDefaultSetupBuildInfo = \case
Just sbi
| PD.Hooks <- PD.buildType pkgdesc ->
-- Fix for #11331; see 'addCabalDepForHooks' for more details.
Just $ addCabalDepForHooks sbi
Nothing
| Just deps <- mbSetupDeps
, PD.buildType pkgdesc == PD.Custom || PD.buildType pkgdesc == PD.Hooks ->
Just $
PD.SetupBuildInfo
{ PD.defaultSetupDepends = True
, PD.setupDepends = deps
}
mbSBI -> mbSBI

-- | Add an implicit dependency on @Cabal@ for a @build-type: Hooks@ package
-- that doesn't explicitly depend on @Cabal@. Rationale: we need the @Cabal@
-- library in order to compile @main = defaultMainWithSetupHooks setupHooks@.
--
-- This ensures the solver picks a consistent version of @Cabal@ when other
-- packages in the @setup-depends@ stanza depend on @Cabal@.
-- See https://github.com/haskell/cabal/issues/11331.
Comment thread
sheaf marked this conversation as resolved.
--
-- NB: don't do this for @build-type: Custom@, as it is possible for such
-- packages to not depend on @Cabal@ at all (although basically unheard of
-- in practice).
addCabalDepForHooks :: PD.SetupBuildInfo -> PD.SetupBuildInfo
addCabalDepForHooks sbi@(PD.SetupBuildInfo{PD.setupDepends = deps})
| any ((== cabalPkgName) . depPkgName) deps =
sbi
| otherwise =
sbi{PD.setupDepends = Dependency cabalPkgName anyVersion mainLibSet : deps}
where
cabalPkgName = mkPackageName "Cabal"

-- | If a package has a custom setup then we need to add a setup-depends
-- on Cabal.
addSetupCabalMinVersionConstraint
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cabal-version: 2.4
name: Cabal
version: 3.16.666.0
library
default-language: Haskell2010
build-depends: stub == 0.1
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
cabal-version: 2.4
name: Cabal
version: 3.16.777.0
library
default-language: Haskell2010
build-depends: base, stub == 0.2
exposed-modules:
Distribution.Simple.SetupHooks
Distribution.Simple
hs-source-dirs: src
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module Distribution.Simple ( defaultMainWithSetupHooks ) where

import System.Exit ( exitFailure )
import Distribution.Simple.SetupHooks ( SetupHooks )

defaultMainWithSetupHooks :: SetupHooks -> IO ()
defaultMainWithSetupHooks _ = do
putStrLn "Chosen GOOD Cabal"
exitFailure
-- NB: we call 'exitFailure' here so that cabal-install, who is invoking
-- this code thinking it is building the package, doesn't try to proceed
-- when actually we haven't done anything (e.g. try to read a package
-- description file).
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module Distribution.Simple.SetupHooks where

data SetupHooks = SetupHooks
14 changes: 14 additions & 0 deletions cabal-testsuite/PackageTests/SetupHooks/T11331/Setup.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{-# LANGUAGE NoImplicitPrelude #-}

module Main where

-- Cabal
import Distribution.Simple ( defaultMainWithSetupHooks )

-- T11331
import SetupHooks ( setupHooks )

--------------------------------------------------------------------------------

main :: IO ()
main = defaultMainWithSetupHooks setupHooks
4 changes: 4 additions & 0 deletions cabal-testsuite/PackageTests/SetupHooks/T11331/SetupHooks.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module SetupHooks (setupHooks) where

-- fancy-hooks
import FancyHooks (setupHooks)
18 changes: 18 additions & 0 deletions cabal-testsuite/PackageTests/SetupHooks/T11331/T11331.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
cabal-version: 3.14
name: T11331
version: 0.1.0.0
synopsis: Test for Cabal bug 11331
license: BSD-3-Clause
author: NA
maintainer: NA
category: Testing
build-type: Hooks

custom-setup
setup-depends: fancy-hooks

library
default-language: Haskell2010
build-depends: stub == 0.1

-- See cabal.test.hs for explanation of this test.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
packages: .
56 changes: 56 additions & 0 deletions cabal-testsuite/PackageTests/SetupHooks/T11331/cabal.test.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import Test.Cabal.Prelude

{- Test for https://github.com/haskell/cabal/issues/11331

This test works by having a package database with two Cabal libraries in it,
a good one (Cabal-good) and a poisoned one (Cabal-bad).

Cabal-good depends on stub == 0.2 and Cabal-bad depends on stub == 0.1.

Moreover, we have a fancy-hooks package in the package database, that has been
built against Cabal-good.

T11331 has the following Cabal file:

T11331.setup --> fancy-hooks
T11331.lib --> stub == 0.1

The test checks that, for the setup component, we correctly use Cabal-good
and not Cabal-bad, as only Cabal-good is compatible with fancy-hooks (correct
ABI hash of Cabal dependency).
-}
main :: IO ()
main = cabalTest $ recordMode DoNotRecord $ withPackageDb $ do
-- Build good package set 'fancy-hooks -> Cabal-good -> stub-0.2' first.
withDirectory "stub-0.2" $ do
setup "configure" []
setup "build" []
setup "register" ["--inplace"]
withDirectory "Cabal-good" $ do
setup "configure" []
setup "build" []
setup "register" ["--inplace"]
withDirectory "fancy-hooks" $ do
setup "configure" []
setup "build" []
setup "register" ["--inplace"]

-- Now build bad package set 'Cabal-bad -> stub-0.1'.
withDirectory "stub-0.1" $ do
setup "configure" []
setup "build" []
setup "register" ["--inplace"]
withDirectory "Cabal-bad" $ do
setup "configure" []
setup "build" []
setup "register" ["--inplace"]

-- Now try to build 'T11331' with cabal-install, using the package database
-- that we carefully crafted above. This tests that cabal-install picks
-- 'Cabal-good' for the setup component of 'T11331', otherwise we will fail.
dbDir <- testPackageDbDir <$> getTestEnv

-- This fails because the fake Cabal-good defaultMain doesn't do anything
Comment thread
sheaf marked this conversation as resolved.
-- except print "Chosen GOOD Cabal".
res <- fails $ cabal' "build" [ "--package-db=" ++ dbDir, "T11331" ]
Comment thread
sheaf marked this conversation as resolved.
assertOutputContains "Chosen GOOD Cabal" res
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
cabal-version: 2.4
name: fancy-hooks
version: 1.0
library
default-language: Haskell2010
build-depends: Cabal
exposed-modules: FancyHooks
hs-source-dirs: src
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{-# LANGUAGE NoImplicitPrelude #-}

module FancyHooks ( setupHooks ) where

import Distribution.Simple.SetupHooks ( SetupHooks(..) )

setupHooks :: SetupHooks
setupHooks = SetupHooks
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cabal-version: 2.4
name: stub
version: 0.1
library
default-language: Haskell2010
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
cabal-version: 2.4
name: stub
version: 0.2
library
default-language: Haskell2010
27 changes: 27 additions & 0 deletions changelog.d/pr-11429.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
synopsis: Ensure consistency of `Cabal` version for `SetupHooks`
packages: [cabal-install]
prs: 11429
issues: 11331
---

When building a package with `build-type: Hooks`, we build an executable which
is invoked during the build process to perform build steps. This executable
needs to be linked against the `Cabal` library, therefore we now add a
dependency on `Cabal` when solving dependencies for the setup stanza.

This fixes a bug which resulted in the solver choosing two inconsistent versions
of the `Cabal` library, avoiding strange error messages like:

```
SetupHooks.hs: error: [GHC-83865]
• Couldn't match expected type ‘Distribution.Verbosity.Verbosity’
with actual type ‘Verbosity’
NB: ‘Distribution.Verbosity.Verbosity’
is defined in ‘Distribution.Verbosity’ in package ‘Cabal-3.16.0.0’
‘Verbosity’
is defined in ‘Distribution.Verbosity’ in package ‘Cabal-3.16.0.0’
```

where the error is that there are two different unit IDs for `Cabal` being
passed when compiling the `SetupHooks` module.
Loading