Skip to content

Commit db4ec66

Browse files
committed
Hooks: use the appropriate Cabal unit ID
This commit updates the logic in Distribution.Client.Dependency, namely addDefaultSetupDependencies, to add an implicit Cabal dependency for the custom setup stanza of packages with build-type: Hooks. This ensures we always pick a version of Cabal that is compatible with whatever other libraries the custom-setup stanza depends on (such as Cabal-hooks). Test in T11331. Fixes #11331
1 parent 6cc9c63 commit db4ec66

15 files changed

Lines changed: 208 additions & 1 deletion

File tree

cabal-install/src/Distribution/Client/Dependency.hs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,17 @@ addDefaultSetupDependencies defaultSetupDeps params =
637637
{ PD.packageDescription =
638638
pkgdesc
639639
{ PD.setupBuildInfo =
640+
-- See 'addCabalDepForHooks' for an explanation of
641+
-- what is going on here.
640642
case PD.setupBuildInfo pkgdesc of
641-
Just sbi -> Just sbi
643+
Just sbi ->
644+
let
645+
sbi' =
646+
case PD.buildType pkgdesc of
647+
PD.Hooks -> addCabalDepForHooks sbi
648+
_ -> sbi
649+
in
650+
Just sbi'
642651
Nothing -> case defaultSetupDeps srcpkg of
643652
Nothing -> Nothing
644653
Just deps
@@ -657,6 +666,26 @@ addDefaultSetupDependencies defaultSetupDeps params =
657666
gpkgdesc = srcpkgDescription srcpkg
658667
pkgdesc = PD.packageDescription gpkgdesc
659668

669+
-- | Add an implicit dependency on @Cabal@ for a @build-type: Hooks@ package
670+
-- that doesn't explicitly depend on @Cabal@. Rationale: we need the @Cabal@
671+
-- library in order to compile @main = defaultMainWithSetupHooks setupHooks@.
672+
--
673+
-- This ensures the solver picks a consistent version of @Cabal@ when other
674+
-- packages in the @setup-depends@ stanza depend on @Cabal@.
675+
-- See https://github.com/haskell/cabal/issues/11331.
676+
--
677+
-- NB: don't do this for @build-type: Custom@, as it is possible for such
678+
-- packages to not depend on @Cabal@ at all (although basically unheard of
679+
-- in practice).
680+
addCabalDepForHooks :: PD.SetupBuildInfo -> PD.SetupBuildInfo
681+
addCabalDepForHooks sbi@(PD.SetupBuildInfo{PD.setupDepends = deps})
682+
| any ((== cabalPkgName) . depPkgName) deps =
683+
sbi
684+
| otherwise =
685+
sbi{PD.setupDepends = Dependency cabalPkgName anyVersion mainLibSet : deps}
686+
where
687+
cabalPkgName = mkPackageName "Cabal"
688+
660689
-- | If a package has a custom setup then we need to add a setup-depends
661690
-- on Cabal.
662691
addSetupCabalMinVersionConstraint
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
cabal-version: 2.4
2+
name: Cabal
3+
version: 3.16.666.0
4+
library
5+
default-language: Haskell2010
6+
build-depends: stub == 0.1
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
cabal-version: 2.4
2+
name: Cabal
3+
version: 3.16.777.0
4+
library
5+
default-language: Haskell2010
6+
build-depends: base, stub == 0.2
7+
exposed-modules:
8+
Distribution.Simple.SetupHooks
9+
Distribution.Simple
10+
hs-source-dirs: src
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module Distribution.Simple ( defaultMainWithSetupHooks ) where
2+
3+
import System.Exit ( exitFailure )
4+
import Distribution.Simple.SetupHooks ( SetupHooks )
5+
6+
defaultMainWithSetupHooks :: SetupHooks -> IO ()
7+
defaultMainWithSetupHooks _ = do
8+
putStrLn "Chosen GOOD Cabal"
9+
exitFailure
10+
-- NB: we call 'exitFailure' here so that cabal-install, who is invoking
11+
-- this code thinking it is building the package, doesn't try to proceed
12+
-- when actually we haven't done anything (e.g. try to read a package
13+
-- description file).
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Distribution.Simple.SetupHooks where
2+
3+
data SetupHooks = SetupHooks
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
3+
module Main where
4+
5+
-- Cabal
6+
import Distribution.Simple ( defaultMainWithSetupHooks )
7+
8+
-- T11331
9+
import SetupHooks ( setupHooks )
10+
11+
--------------------------------------------------------------------------------
12+
13+
main :: IO ()
14+
main = defaultMainWithSetupHooks setupHooks
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module SetupHooks (setupHooks) where
2+
3+
-- fancy-hooks
4+
import FancyHooks (setupHooks)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
cabal-version: 3.14
2+
name: T11331
3+
version: 0.1.0.0
4+
synopsis: Test for Cabal bug 11331
5+
license: BSD-3-Clause
6+
author: NA
7+
maintainer: NA
8+
category: Testing
9+
build-type: Hooks
10+
11+
custom-setup
12+
setup-depends: fancy-hooks
13+
14+
library
15+
default-language: Haskell2010
16+
build-depends: stub == 0.1
17+
18+
-- See cabal.test.hs for explanation of this test.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
packages: .
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import Test.Cabal.Prelude
2+
3+
{- Test for https://github.com/haskell/cabal/issues/11331
4+
5+
This test works by having a package database with two Cabal libraries in it,
6+
a good one (Cabal-good) and a poisoned one (Cabal-bad).
7+
8+
Cabal-good depends on stub == 0.2 and Cabal-bad depends on stub == 0.1.
9+
10+
Moreover, we have a fancy-hooks package in the package database, that has been
11+
built against Cabal-good.
12+
13+
T11331 has the following Cabal file:
14+
15+
T11331.setup --> fancy-hooks
16+
T11331.lib --> stub == 0.1
17+
18+
The test checks that, for the setup component, we correctly use Cabal-good
19+
and not Cabal-bad, as only Cabal-good is compatible with fancy-hooks (correct
20+
ABI hash of Cabal dependency).
21+
-}
22+
main :: IO ()
23+
main = cabalTest $ recordMode DoNotRecord $ withPackageDb $ do
24+
-- Build good package set 'fancy-hooks -> Cabal-good -> stub-0.2' first.
25+
withDirectory "stub-0.2" $ do
26+
setup "configure" []
27+
setup "build" []
28+
setup "register" ["--inplace"]
29+
withDirectory "Cabal-good" $ do
30+
setup "configure" []
31+
setup "build" []
32+
setup "register" ["--inplace"]
33+
withDirectory "fancy-hooks" $ do
34+
setup "configure" []
35+
setup "build" []
36+
setup "register" ["--inplace"]
37+
38+
-- Now build bad package set 'Cabal-bad -> stub-0.1'.
39+
withDirectory "stub-0.1" $ do
40+
setup "configure" []
41+
setup "build" []
42+
setup "register" ["--inplace"]
43+
withDirectory "Cabal-bad" $ do
44+
setup "configure" []
45+
setup "build" []
46+
setup "register" ["--inplace"]
47+
48+
-- Now try to build 'T11331' with cabal-install, using the package database
49+
-- that we carefully crafted above. This tests that cabal-install picks
50+
-- 'Cabal-good' for the setup component of 'T11331', otherwise we will fail.
51+
dbDir <- testPackageDbDir <$> getTestEnv
52+
53+
-- This fails because the fake Cabal-good defaultMain doesn't do anything
54+
-- except print "Chosen GOOD Cabal".
55+
res <- fails $ cabal' "build" [ "--package-db=" ++ dbDir, "T11331" ]
56+
assertOutputContains "Chosen GOOD Cabal" res

0 commit comments

Comments
 (0)