diff --git a/Cabal/src/Distribution/Simple/GHC/Build.hs b/Cabal/src/Distribution/Simple/GHC/Build.hs index a49b0773b5c..3d3dc3de1e6 100644 --- a/Cabal/src/Distribution/Simple/GHC/Build.hs +++ b/Cabal/src/Distribution/Simple/GHC/Build.hs @@ -5,7 +5,8 @@ module Distribution.Simple.GHC.Build where import Distribution.Compat.Prelude import Prelude () -import Control.Monad.IO.Class +import qualified Distribution.Compat.Graph as Graph + import Distribution.PackageDescription as PD hiding (buildInfo) import Distribution.Simple.Build.Inputs import Distribution.Simple.Flag (Flag) @@ -25,6 +26,8 @@ import Distribution.Utils.NubList (fromNubListR) import Distribution.Utils.Path import Distribution.Verbosity (VerbosityHandles, mkVerbosity, verbosityHandles) + +import Control.Monad.IO.Class import System.FilePath (splitDirectories) {- Note [Build Target Dir vs Target Dir] @@ -75,7 +78,7 @@ build numJobs verbHandles pkg_descr pbci = do verbosity = mkVerbosity verbHandles $ buildVerbosity pbci isLib = buildIsLib pbci lbi = localBuildInfo pbci - bi = buildBI pbci + comp = buildComponent pbci clbi = buildCLBI pbci isIndef = componentIsIndefinite clbi mbWorkDir = mbWorkDirLBI lbi @@ -118,9 +121,35 @@ build numJobs verbHandles pkg_descr pbci = do let wantedWays@(wantedLibWays, wantedFLibWay, wantedExeWay) = buildWays lbi -- Ways which are needed due to the compiler configuration - let doingTH = usesTemplateHaskellOrQQ bi + let doingTH = + -- Does this component, or another component that (transitively) depends + -- on this component, use TemplateHaskell or QuasiQuotes? + -- + -- Ticket #7684 showed that we need to take into account intra-package + -- dependencies. + any usesTemplateHaskellOrQQ thisCompAndReverseDepsBuildInfos + + -- The BuildInfos for this component and all of the components that + -- transitively depend on it (its reverse dependencies). + thisCompAndReverseDepsBuildInfos = + [ componentBuildInfo revDepComp + | let compUnitId = componentUnitId clbi + , -- 'revClosure' retrieves components that depend on this component. + revDepCLBI <- fromMaybe [clbi] $ Graph.revClosure (componentGraph lbi) [compUnitId] + , -- Use 'lookupComponent' here; don't use any function that goes via + -- 'getComponent' (e.g. mkTargetInfo or unitIdTarget'), as that will + -- tiresomely cause an error for 'detailed-0.9' test-suites because + -- 'testSuiteLibV09AsLibAndExe' creates a stub PackageDescription with + -- most components zeroed out. + -- + -- The implementation below means we will get 'Nothing' when the + -- current component is a 'detailed-0.9' test-suite, which is fine + -- as nothing can depend on a test-suite. + Just revDepComp <- [lookupComponent pkg_descr $ componentLocalName revDepCLBI] + ] + defaultGhcWay = compilerBuildWay (buildCompiler pbci) - wantedModBuildWays = case buildComponent pbci of + wantedModBuildWays = case comp of CLib _ -> wantedLibWays isIndef CFLib fl -> [wantedFLibWay (withDynFLib fl)] CExe _ -> [wantedExeWay] @@ -129,7 +158,7 @@ build numJobs verbHandles pkg_descr pbci = do finalModBuildWays = wantedModBuildWays ++ [defaultGhcWay | doingTH && defaultGhcWay `notElem` wantedModBuildWays] - compNameStr = showComponentName $ componentName $ buildComponent pbci + compNameStr = showComponentName $ componentName comp liftIO $ info verbosity ("Wanted module build ways(" ++ compNameStr ++ "): " ++ show wantedModBuildWays) liftIO $ info verbosity ("Final module build ways(" ++ compNameStr ++ "): " ++ show finalModBuildWays) diff --git a/cabal-testsuite/PackageTests/T7684/T7684.cabal b/cabal-testsuite/PackageTests/T7684/T7684.cabal new file mode 100644 index 00000000000..946b3d80ca3 --- /dev/null +++ b/cabal-testsuite/PackageTests/T7684/T7684.cabal @@ -0,0 +1,24 @@ +cabal-version: 2.2 +name: T7684 +version: 0.1.0.0 +license: BSD-3-Clause +author: Matthew Pickering +maintainer: The Cabal team +build-type: Simple +synopsis: Test for Cabal bug #7684 +description: + Check that we compile sublibraries in the dynamic way when that is needed + due to TemplateHaskell or QuasiQuotes in another component that depends on it. + +library library-a + hs-source-dirs: lib-a + exposed-modules: A + build-depends: base, template-haskell + + default-language: Haskell2010 + +library + hs-source-dirs: lib + exposed-modules: B + build-depends: base, library-a + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/T7684/cabal.project b/cabal-testsuite/PackageTests/T7684/cabal.project new file mode 100644 index 00000000000..07e44184afb --- /dev/null +++ b/cabal-testsuite/PackageTests/T7684/cabal.project @@ -0,0 +1,4 @@ +packages: . + +shared: False +executable-dynamic: False diff --git a/cabal-testsuite/PackageTests/T7684/cabal.test.hs b/cabal-testsuite/PackageTests/T7684/cabal.test.hs new file mode 100644 index 00000000000..e9b36b277ad --- /dev/null +++ b/cabal-testsuite/PackageTests/T7684/cabal.test.hs @@ -0,0 +1,5 @@ +import Test.Cabal.Prelude + +main = setupAndCabalTest $ recordMode DoNotRecord $ do + setup "configure" [] + setup "build" [] diff --git a/cabal-testsuite/PackageTests/T7684/lib-a/A.hs b/cabal-testsuite/PackageTests/T7684/lib-a/A.hs new file mode 100644 index 00000000000..8d50cff8a13 --- /dev/null +++ b/cabal-testsuite/PackageTests/T7684/lib-a/A.hs @@ -0,0 +1,8 @@ +{-# LANGUAGE TemplateHaskellQuotes #-} + +module A where + +import Language.Haskell.TH.Syntax ( Q, Exp ) + +a :: Q Exp +a = [| putStrLn "a" |] diff --git a/cabal-testsuite/PackageTests/T7684/lib/B.hs b/cabal-testsuite/PackageTests/T7684/lib/B.hs new file mode 100644 index 00000000000..0a073c2eca3 --- /dev/null +++ b/cabal-testsuite/PackageTests/T7684/lib/B.hs @@ -0,0 +1,7 @@ +{-# LANGUAGE TemplateHaskell #-} + +module B where + +import A + +main = $(a) diff --git a/changelog.d/IntraPackageDyn.md b/changelog.d/IntraPackageDyn.md new file mode 100644 index 00000000000..18d139b5bfa --- /dev/null +++ b/changelog.d/IntraPackageDyn.md @@ -0,0 +1,11 @@ +--- +synopsis: Build dynamic libraries when needed for intra-package dependencies +packages: [Cabal] +prs: 11791 +issues: 7684 +--- + +When building a package with a sublibrary, Cabal now properly takes into account +intra-package dependencies when deciding whether each sublibrary should be built +in the dynamic way (e.g. because another library that depends on it uses +TemplateHaskell or QuasiQuotes).