From 1549a7acdcad58bf4e9469ab251044573d387ac3 Mon Sep 17 00:00:00 2001 From: Matthew Pickering Date: Fri, 28 Mar 2025 16:42:28 +0000 Subject: [PATCH] multi-repl: Support module renaming for ghc-9.12 onwards In ghc-9.12 the -rexported-module flag was extended to add support for module renaming. Therefore now if a module uses a module renaming, then the -reexported-module flag is passed the renaming. Fixes #10181 --- Cabal/src/Distribution/Simple/Compiler.hs | 9 +++++ Cabal/src/Distribution/Simple/Errors.hs | 9 +++++ .../src/Distribution/Simple/GHC/Build/Link.hs | 40 +++++++++++++------ .../MultiRepl/ReexportedModule/cabal.project | 2 + .../MultiRepl/ReexportedModule/cabal.test.hs | 15 +++++++ .../ReexportedModule/package-a/CHANGELOG.md | 5 +++ .../package-a/package-a.cabal | 19 +++++++++ .../package-a/src/PackageA.hs | 2 + .../ReexportedModule/package-b/CHANGELOG.md | 5 +++ .../package-b/package-b.cabal | 18 +++++++++ .../package-b/src/PackageB.hs | 10 +++++ changelog.d/pr-10880.md | 12 ++++++ 12 files changed, 134 insertions(+), 12 deletions(-) create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.project create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.test.hs create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/CHANGELOG.md create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/package-a.cabal create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/src/PackageA.hs create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/CHANGELOG.md create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/package-b.cabal create mode 100644 cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/src/PackageB.hs create mode 100644 changelog.d/pr-10880.md diff --git a/Cabal/src/Distribution/Simple/Compiler.hs b/Cabal/src/Distribution/Simple/Compiler.hs index c24de767172..346c4c82125 100644 --- a/Cabal/src/Distribution/Simple/Compiler.hs +++ b/Cabal/src/Distribution/Simple/Compiler.hs @@ -84,6 +84,7 @@ module Distribution.Simple.Compiler , libraryDynDirSupported , libraryVisibilitySupported , jsemSupported + , reexportedAsSupported -- * Support for profiling detail levels , ProfDetailLevel (..) @@ -432,6 +433,14 @@ jsemSupported comp = case compilerFlavor comp of where v = compilerVersion comp +-- | Does the compiler support the -reexported-modules "A as B" syntax +reexportedAsSupported :: Compiler -> Bool +reexportedAsSupported comp = case compilerFlavor comp of + GHC -> v >= mkVersion [9, 12] + _ -> False + where + v = compilerVersion comp + -- | Does this compiler support a package database entry with: -- "dynamic-library-dirs"? libraryDynDirSupported :: Compiler -> Bool diff --git a/Cabal/src/Distribution/Simple/Errors.hs b/Cabal/src/Distribution/Simple/Errors.hs index 1ce4f7ca06a..78e20a25854 100644 --- a/Cabal/src/Distribution/Simple/Errors.hs +++ b/Cabal/src/Distribution/Simple/Errors.hs @@ -171,6 +171,7 @@ data CabalException | UnknownVersionDb String VersionRange FilePath | MissingCoveredInstalledLibrary UnitId | SetupHooksException SetupHooksException + | MultiReplDoesNotSupportComplexReexportedModules PackageName ComponentName deriving (Show) exceptionCode :: CabalException -> Int @@ -304,6 +305,7 @@ exceptionCode e = case e of MissingCoveredInstalledLibrary{} -> 9341 SetupHooksException err -> setupHooksExceptionCode err + MultiReplDoesNotSupportComplexReexportedModules{} -> 9355 versionRequirement :: VersionRange -> String versionRequirement range @@ -799,3 +801,10 @@ exceptionMessage e = case e of ++ "' in package database stack." SetupHooksException err -> setupHooksExceptionMessage err + MultiReplDoesNotSupportComplexReexportedModules pname cname -> + "When attempting start the repl for " + ++ showComponentName cname + ++ " from package " + ++ prettyShow pname + ++ " a module renaming was found.\n" + ++ "Multi-repl does not work with complicated reexported-modules until GHC-9.12." diff --git a/Cabal/src/Distribution/Simple/GHC/Build/Link.hs b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs index e26e3890ba3..962d0d95c7a 100644 --- a/Cabal/src/Distribution/Simple/GHC/Build/Link.hs +++ b/Cabal/src/Distribution/Simple/GHC/Build/Link.hs @@ -7,9 +7,11 @@ module Distribution.Simple.GHC.Build.Link where import Distribution.Compat.Prelude import Prelude () +import Control.Monad import Control.Monad.IO.Class import qualified Data.ByteString.Lazy.Char8 as BS import qualified Data.Set as Set +import Distribution.Backpack import Distribution.Compat.Binary (encode) import Distribution.Compat.ResponseFile import Distribution.InstalledPackageInfo (InstalledPackageInfo) @@ -23,6 +25,7 @@ import Distribution.Pretty import Distribution.Simple.Build.Inputs import Distribution.Simple.BuildPaths import Distribution.Simple.Compiler +import Distribution.Simple.Errors import Distribution.Simple.GHC.Build.Modules import Distribution.Simple.GHC.Build.Utils (exeTargetName, flibBuildName, flibTargetName, withDynFLib) import Distribution.Simple.GHC.ImplInfo @@ -740,6 +743,7 @@ runReplOrWriteFlags runReplOrWriteFlags ghcProg lbi rflags ghcOpts pkg_name target = let bi = componentBuildInfo $ targetComponent target clbi = targetCLBI target + cname = componentName (targetComponent target) comp = compiler lbi platform = hostPlatform lbi common = configCommonFlags $ configFlags lbi @@ -761,21 +765,32 @@ runReplOrWriteFlags ghcProg lbi rflags ghcOpts pkg_name target = Flag out_dir -> do let uid = componentUnitId clbi this_unit = prettyShow uid + getOpenModName (OpenModule _ mn) = Just mn + getOpenModName (OpenModuleVar{}) = Nothing reexported_modules = - [ mn | LibComponentLocalBuildInfo{componentExposedModules = exposed_mods} <- [clbi], IPI.ExposedModule mn (Just{}) <- exposed_mods + [ (from_mn, to_mn) | LibComponentLocalBuildInfo{componentExposedModules = exposed_mods} <- [clbi], IPI.ExposedModule to_mn (Just m) <- exposed_mods, Just from_mn <- [getOpenModName m] ] + renderReexportedModule (from_mn, to_mn) + | reexportedAsSupported comp = + pure $ prettyShow from_mn ++ " as " ++ prettyShow to_mn + | otherwise = + if from_mn == to_mn + then pure $ prettyShow to_mn + else dieWithException verbosity (MultiReplDoesNotSupportComplexReexportedModules pkg_name cname) hidden_modules = otherModules bi - extra_opts = - concat $ - [ ["-this-package-name", prettyShow pkg_name] - , case mbWorkDir of - Nothing -> [] - Just wd -> ["-working-dir", getSymbolicPath wd] - ] - ++ [ ["-reexported-module", prettyShow m] | m <- reexported_modules - ] - ++ [ ["-hidden-module", prettyShow m] | m <- hidden_modules - ] + render_extra_opts = do + rexp_mods <- mapM renderReexportedModule reexported_modules + pure $ + concat $ + [ ["-this-package-name", prettyShow pkg_name] + , case mbWorkDir of + Nothing -> [] + Just wd -> ["-working-dir", getSymbolicPath wd] + ] + ++ [ ["-reexported-module", m] | m <- rexp_mods + ] + ++ [ ["-hidden-module", prettyShow m] | m <- hidden_modules + ] -- Create "paths" subdirectory if it doesn't exist. This is where we write -- information about how the PATH was augmented. createDirectoryIfMissing False (out_dir "paths") @@ -783,6 +798,7 @@ runReplOrWriteFlags ghcProg lbi rflags ghcOpts pkg_name target = writeFileAtomic (out_dir "paths" this_unit) (encode ghcProg) -- Write out options for this component into a file ready for loading into -- the multi-repl + extra_opts <- render_extra_opts writeFileAtomic (out_dir this_unit) $ BS.pack $ escapeArgs $ diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.project b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.project new file mode 100644 index 00000000000..5c1930664c8 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.project @@ -0,0 +1,2 @@ +packages: package-a package-b +multi-repl: true diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.test.hs b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.test.hs new file mode 100644 index 00000000000..62d18087ec7 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/cabal.test.hs @@ -0,0 +1,15 @@ +import Test.Cabal.Prelude + +main = cabalTest $ recordMode DoNotRecord $ do + -- For the multi-repl command + good_ver <- isGhcVersion ">= 9.12" + skipUnlessGhcVersion ">= 9.4" + skipUnlessAnyCabalVersion ">= 3.15" + if good_ver + then do + res <- cabalWithStdin "v2-repl" ["all"] "" + assertOutputContains "Ok, two" res + else do + res <- fails $ cabalWithStdin "v2-repl" ["all"] "" + assertOutputContains "Multi-repl does not work with complicated" res + diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/CHANGELOG.md b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/CHANGELOG.md new file mode 100644 index 00000000000..233761f5fb9 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for package-a + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/package-a.cabal b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/package-a.cabal new file mode 100644 index 00000000000..df3e89dca13 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/package-a.cabal @@ -0,0 +1,19 @@ +cabal-version: 3.14 +name: package-a +version: 0.1.0.0 +license: NONE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: PackageA + reexported-modules: Prelude as PreludeA + build-depends: base + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/src/PackageA.hs b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/src/PackageA.hs new file mode 100644 index 00000000000..9abd25cc649 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-a/src/PackageA.hs @@ -0,0 +1,2 @@ +module PackageA () where + diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/CHANGELOG.md b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/CHANGELOG.md new file mode 100644 index 00000000000..be7e8473685 --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for package-b + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/package-b.cabal b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/package-b.cabal new file mode 100644 index 00000000000..46e3c7a3d6b --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/package-b.cabal @@ -0,0 +1,18 @@ +cabal-version: 3.14 +name: package-b +version: 0.1.0.0 +license: NONE +author: Matthew Pickering +maintainer: matthewtpickering@gmail.com +build-type: Simple +extra-doc-files: CHANGELOG.md + +common warnings + ghc-options: -Wall + +library + import: warnings + exposed-modules: PackageB + build-depends: package-a + hs-source-dirs: src + default-language: Haskell2010 diff --git a/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/src/PackageB.hs b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/src/PackageB.hs new file mode 100644 index 00000000000..692fffd413b --- /dev/null +++ b/cabal-testsuite/PackageTests/MultiRepl/ReexportedModule/package-b/src/PackageB.hs @@ -0,0 +1,10 @@ +{-# LANGUAGE NoImplicitPrelude #-} +module PackageB (someFunc) where + +-- reexport from package-a +import PreludeA +-- Normal import from package-a +import PackageA () + +someFunc :: IO () +someFunc = putStrLn "someFunc" diff --git a/changelog.d/pr-10880.md b/changelog.d/pr-10880.md new file mode 100644 index 00000000000..6b8defe7eb5 --- /dev/null +++ b/changelog.d/pr-10880.md @@ -0,0 +1,12 @@ +--- +synopsis: 'Fix multi-repl when using reexported-modules with renaming for GHC >= 9.12' +packages: [cabal-install, Cabal] +prs: 10880 +issues: 10181 +--- + +Since GHC 9.12, the `-reexported-module` flag has supported module renaming. Therefore +we now use that functionality when starting the multi-repl if it is needed. A new +error message is added to catch the case where you attempt to load a project which +uses this complicated export form but are using < 9.12. +