Hannes Siebenhandl pushed to branch wip/fendor/dep-json at Glasgow Haskell Compiler / GHC
Commits:
-
b2eed73f
by fendor at 2026-09-25T14:48:04+02:00
-
d87108e8
by fendor at 2026-09-25T15:58:43+02:00
-
01b023a0
by fendor at 2026-09-25T15:58:46+02:00
-
b5351fd6
by fendor at 2026-09-25T15:58:47+02:00
-
663da77b
by fendor at 2026-09-29T17:17:07+02:00
-
0963547e
by fendor at 2026-10-01T16:25:24+02:00
30 changed files:
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/MakeFile.hs
- compiler/GHC/Driver/Pipeline.hs
- compiler/GHC/Driver/Pipeline/Execute.hs
- compiler/GHC/Driver/Pipeline/Phases.hs
- compiler/GHC/Driver/Session.hs
- docs/users_guide/separate_compilation.rst
- testsuite/driver/testlib.py
- + testsuite/tests/driver/T24384/A.hs
- + testsuite/tests/driver/T24384/C.hs
- + testsuite/tests/driver/T24384/C.hs-boot
- + testsuite/tests/driver/T24384/D.hs
- + testsuite/tests/driver/T24384/E.hs
- + testsuite/tests/driver/T24384/Makefile
- + testsuite/tests/driver/T24384/T24384a.stdout
- + testsuite/tests/driver/T24384/T24384b.stdout
- + testsuite/tests/driver/T24384/T24384b.stdout-mingw
- + testsuite/tests/driver/T24384/T24384c.stdout
- + testsuite/tests/driver/T24384/all.T
- + testsuite/tests/driver/T24384/dep-internal/DepInternal.hs
- + testsuite/tests/driver/T24384/dep-internal/dep-internal.pkg
- + testsuite/tests/driver/T24384/dep-public/DepPublic.hs
- + testsuite/tests/driver/T24384/dep-public/dep-public.pkg
- + testsuite/tests/driver/T24384/dep/Dep.hs
- + testsuite/tests/driver/T24384/dep/dep.pkg
- + testsuite/tests/driver/T24384/foo.h
- + testsuite/tests/driver/T24384/format_json.sh
- + testsuite/tests/driver/T24384/lib/B.hs
- + testsuite/tests/driver/T24384/lib/B.hs-boot
- + testsuite/tests/driver/T24384/preproc.sh
Changes:
| ... | ... | @@ -351,6 +351,7 @@ data DynFlags = DynFlags { |
| 351 | 351 | |
| 352 | 352 | -- For ghc -M
|
| 353 | 353 | depMakefile :: FilePath,
|
| 354 | + depJson :: Maybe FilePath,
|
|
| 354 | 355 | depIncludePkgDeps :: Bool,
|
| 355 | 356 | depIncludeCppDeps :: Bool,
|
| 356 | 357 | depExcludeMods :: [ModuleName],
|
| ... | ... | @@ -694,6 +695,7 @@ defaultDynFlags mySettings = |
| 694 | 695 | |
| 695 | 696 | -- ghc -M values
|
| 696 | 697 | depMakefile = "Makefile",
|
| 698 | + depJson = Nothing,
|
|
| 697 | 699 | depIncludePkgDeps = False,
|
| 698 | 700 | depIncludeCppDeps = False,
|
| 699 | 701 | depExcludeMods = [],
|
| ... | ... | @@ -7,6 +7,8 @@ |
| 7 | 7 | -- (c) The University of Glasgow 2005
|
| 8 | 8 | --
|
| 9 | 9 | -----------------------------------------------------------------------------
|
| 10 | +{-# LANGUAGE DerivingVia #-}
|
|
| 11 | +{-# LANGUAGE RecordWildCards #-}
|
|
| 10 | 12 | |
| 11 | 13 | module GHC.Driver.MakeFile
|
| 12 | 14 | ( doMkDependHS
|
| ... | ... | @@ -16,47 +18,68 @@ where |
| 16 | 18 | |
| 17 | 19 | import GHC.Prelude
|
| 18 | 20 | |
| 19 | -import qualified GHC
|
|
| 20 | -import GHC.Driver.Make
|
|
| 21 | -import GHC.Driver.Monad
|
|
| 21 | +import GHC qualified
|
|
| 22 | + |
|
| 23 | +import GHC.Data.Bag (listToBag)
|
|
| 24 | +import GHC.Data.FastString (lexicalCompareFS, unpackFS)
|
|
| 25 | +import GHC.Data.Graph.Directed (SCC (..))
|
|
| 26 | +import GHC.Data.OsPath
|
|
| 27 | + |
|
| 22 | 28 | import GHC.Driver.DynFlags
|
| 23 | -import GHC.Utils.Misc
|
|
| 24 | 29 | import GHC.Driver.Env
|
| 25 | 30 | import GHC.Driver.Errors.Types
|
| 26 | -import GHC.Types.UnresolvedImport
|
|
| 27 | -import qualified GHC.SysTools as SysTools
|
|
| 28 | -import GHC.Data.Graph.Directed ( SCC(..) )
|
|
| 29 | -import GHC.Data.OsPath (unsafeDecodeUtf)
|
|
| 30 | -import GHC.Utils.Outputable
|
|
| 31 | -import GHC.Utils.Panic
|
|
| 32 | -import GHC.Types.SourceError
|
|
| 33 | -import GHC.Types.SrcLoc
|
|
| 34 | -import GHC.Types.PkgQual
|
|
| 35 | -import Data.List (partition)
|
|
| 36 | -import GHC.Utils.TmpFs
|
|
| 31 | +import GHC.Driver.Make
|
|
| 32 | +import GHC.Driver.Monad
|
|
| 33 | +import GHC.Driver.Phases
|
|
| 34 | +import GHC.Driver.Pipeline
|
|
| 35 | +import GHC.Driver.Pipeline.Monad
|
|
| 36 | +import GHC.Driver.Session
|
|
| 37 | 37 | |
| 38 | +import GHC.Iface.Errors.Types
|
|
| 38 | 39 | import GHC.Iface.Load (cannotFindModule)
|
| 39 | 40 | |
| 41 | +import GHC.SysTools qualified as SysTools
|
|
| 42 | +import GHC.Types.PkgQual
|
|
| 43 | +import GHC.Types.SourceError
|
|
| 44 | +import GHC.Types.SrcLoc
|
|
| 45 | +import GHC.Types.Unique.Set (UniqSet)
|
|
| 46 | +import GHC.Types.Unique.Set qualified as UniqSet
|
|
| 47 | +import GHC.Types.UnresolvedImport
|
|
| 48 | + |
|
| 49 | +import GHC.Unit.Finder
|
|
| 50 | +import GHC.Unit.Info
|
|
| 40 | 51 | import GHC.Unit.Module
|
| 41 | -import GHC.Unit.Module.ModSummary
|
|
| 42 | 52 | import GHC.Unit.Module.Graph
|
| 43 | -import GHC.Unit.Finder
|
|
| 53 | +import GHC.Unit.Module.ModSummary
|
|
| 54 | +import GHC.Unit.State (lookupUnitId)
|
|
| 44 | 55 | |
| 45 | -import GHC.Utils.Exception
|
|
| 46 | 56 | import GHC.Utils.Error
|
| 57 | +import GHC.Utils.Exception
|
|
| 58 | +import GHC.Utils.Json
|
|
| 47 | 59 | import GHC.Utils.Logger
|
| 60 | +import GHC.Utils.Misc
|
|
| 61 | +import GHC.Utils.Outputable
|
|
| 62 | +import GHC.Utils.Panic
|
|
| 63 | +import GHC.Utils.TmpFs
|
|
| 48 | 64 | |
| 65 | +import Control.Monad (when)
|
|
| 66 | +import Data.Either
|
|
| 67 | +import Data.Foldable (traverse_)
|
|
| 68 | +import Data.IORef
|
|
| 69 | +import Data.List (partition)
|
|
| 70 | +import Data.Map.Strict qualified as Map
|
|
| 71 | +import Data.Maybe (isJust, isNothing)
|
|
| 72 | +import Data.Semigroup qualified as Semigroup
|
|
| 73 | +import Data.Set qualified as Set
|
|
| 74 | +import GHC.Generics (Generic, Generically (..))
|
|
| 49 | 75 | import System.Directory
|
| 50 | -import System.FilePath
|
|
| 76 | +import qualified System.Directory as Directory
|
|
| 77 | +import System.OsPath as OsPath
|
|
| 51 | 78 | import System.IO
|
| 52 | -import System.IO.Error ( isEOFError )
|
|
| 53 | -import Control.Monad ( when, forM_ )
|
|
| 54 | -import Data.Maybe ( isJust )
|
|
| 55 | -import Data.IORef
|
|
| 56 | -import qualified Data.Set as Set
|
|
| 57 | -import GHC.Iface.Errors.Types
|
|
| 58 | -import Data.Either
|
|
| 59 | -import GHC.Data.Bag (listToBag)
|
|
| 79 | +import System.IO.Error (isEOFError)
|
|
| 80 | +import qualified System.OsString as OsString
|
|
| 81 | +import qualified Data.Monoid as Monoid
|
|
| 82 | +import qualified System.FilePath as FilePath
|
|
| 60 | 83 | |
| 61 | 84 | -----------------------------------------------------------------
|
| 62 | 85 | --
|
| ... | ... | @@ -98,27 +121,47 @@ doMkDependHS srcs = do |
| 98 | 121 | |
| 99 | 122 | doMkDependModuleGraph :: GhcMonad m => DynFlags -> ModuleGraph -> m ()
|
| 100 | 123 | doMkDependModuleGraph dflags module_graph = do
|
| 124 | + hsc_env <- getSession
|
|
| 101 | 125 | logger <- getLogger
|
| 102 | - tmpfs <- hsc_tmpfs <$> getSession
|
|
| 103 | - let excl_mods = depExcludeMods dflags
|
|
| 126 | + let
|
|
| 127 | + tmpfs = hsc_tmpfs hsc_env
|
|
| 128 | + excl_mods = depExcludeMods dflags
|
|
| 104 | 129 | |
| 105 | - files <- liftIO $ beginMkDependHS logger tmpfs dflags
|
|
| 106 | - let sorted = GHC.topSortModuleGraph False module_graph Nothing
|
|
| 130 | + root_ <- liftIO getCurrentDirectory
|
|
| 131 | + root <- encodeUtf root_
|
|
| 107 | 132 | |
| 133 | + let
|
|
| 134 | + backends = concat
|
|
| 135 | + [ [ initFileDepWriter logger root tmpfs dflags
|
|
| 136 | + ]
|
|
| 137 | + , [ initJsonDepWriter json_output dflags
|
|
| 138 | + | Just json_output <- [depJson dflags]
|
|
| 139 | + ]
|
|
| 140 | + ]
|
|
| 141 | + |
|
| 142 | + |
|
| 143 | + let sorted = GHC.topSortModuleGraph False module_graph Nothing
|
|
| 108 | 144 | -- Print out the dependencies if wanted
|
| 109 | 145 | liftIO $ debugTraceMsg logger 2 (text "Module dependencies" $$ ppr sorted)
|
| 110 | 146 | |
| 111 | - -- Process them one by one, dumping results into makefile
|
|
| 112 | - -- and complaining about cycles
|
|
| 113 | - hsc_env <- getSession
|
|
| 114 | - root <- liftIO getCurrentDirectory
|
|
| 115 | - mapM_ (liftIO . processDeps dflags hsc_env excl_mods root (mkd_tmp_hdl files)) sorted
|
|
| 147 | + liftIO $ do
|
|
| 148 | + |
|
| 149 | + -- Setup the writers
|
|
| 150 | + writers <- sequenceA backends
|
|
| 151 | + sinks <- traverse dw_beginWriter writers
|
|
| 152 | + |
|
| 153 | + -- Do the actual work
|
|
| 154 | + do
|
|
| 155 | + -- Process them one by one, dumping results and complaining about cycles
|
|
| 156 | + mapM_ (processDeps dflags hsc_env (UniqSet.mkUniqSet excl_mods) sinks) sorted
|
|
| 116 | 157 | |
| 117 | - -- If -ddump-mod-cycles, show cycles in the module graph
|
|
| 118 | - liftIO $ dumpModCycles logger module_graph
|
|
| 158 | + -- If -ddump-mod-cycles, show cycles in the module graph
|
|
| 159 | + liftIO $ dumpModCycles logger module_graph
|
|
| 160 | + |
|
| 161 | + -- Tidy up
|
|
| 162 | + do
|
|
| 163 | + traverse_ dw_endWriter writers
|
|
| 119 | 164 | |
| 120 | - -- Tidy up
|
|
| 121 | - liftIO $ endMkDependHS logger files
|
|
| 122 | 165 | |
| 123 | 166 | -- Unconditional exiting is a bad idea. If an error occurs we'll get an
|
| 124 | 167 | --exception; if that is not caught it's fine, but at least we have a
|
| ... | ... | @@ -127,6 +170,200 @@ doMkDependModuleGraph dflags module_graph = do |
| 127 | 170 | |
| 128 | 171 | --`GHC.ghcCatch` \_ -> io $ exitWith (ExitFailure 1)
|
| 129 | 172 | |
| 173 | +--------------------------------------------------------------------------------
|
|
| 174 | +-- Types abstracting over the output
|
|
| 175 | +--------------------------------------------------------------------------------
|
|
| 176 | + |
|
| 177 | +data DepNode =
|
|
| 178 | + DepNode
|
|
| 179 | + { dn_mod :: ModuleWithIsBoot
|
|
| 180 | + , dn_src :: OsPath
|
|
| 181 | + , dn_obj :: OsPath
|
|
| 182 | + , dn_hi :: OsPath
|
|
| 183 | + , dn_preprocessing :: PreprocessingNode
|
|
| 184 | + }
|
|
| 185 | + |
|
| 186 | +data PreprocessingNode = PreprocessingNode
|
|
| 187 | + { pn_preprocessor :: Maybe String
|
|
| 188 | + , pn_options :: [String]
|
|
| 189 | + }
|
|
| 190 | + |
|
| 191 | +data Dep
|
|
| 192 | + = DepHi
|
|
| 193 | + { dep_mod :: Module
|
|
| 194 | + , dep_path :: OsPath
|
|
| 195 | + , dep_unit :: Maybe UnitInfo
|
|
| 196 | + , dep_local :: Bool
|
|
| 197 | + , dep_level :: ImportLevel
|
|
| 198 | + , dep_boot :: IsBootInterface
|
|
| 199 | + }
|
|
| 200 | + | DepCpp
|
|
| 201 | + { dep_path :: OsPath
|
|
| 202 | + }
|
|
| 203 | + |
|
| 204 | +data DependencyWriter = DependencyWriter
|
|
| 205 | + { dw_beginWriter :: IO DepSink
|
|
| 206 | + , dw_endWriter :: IO ()
|
|
| 207 | + }
|
|
| 208 | + |
|
| 209 | +data DepSink = DepSink
|
|
| 210 | + { ds_writeDependency :: DepNode -> [Dep] -> IO ()
|
|
| 211 | + }
|
|
| 212 | + |
|
| 213 | +-----------------------------------------------------------------
|
|
| 214 | +--
|
|
| 215 | +-- processDeps
|
|
| 216 | +--
|
|
| 217 | +-----------------------------------------------------------------
|
|
| 218 | + |
|
| 219 | +processDeps :: DynFlags
|
|
| 220 | + -> HscEnv
|
|
| 221 | + -> UniqSet ModuleName -- ^ Excludes
|
|
| 222 | + -> [DepSink]
|
|
| 223 | + -> SCC ModuleGraphNode
|
|
| 224 | + -> IO ()
|
|
| 225 | +-- Write suitable dependencies to handle
|
|
| 226 | +-- Always:
|
|
| 227 | +-- this.o : this.hs
|
|
| 228 | +--
|
|
| 229 | +-- If the dependency is on something other than a .hi file:
|
|
| 230 | +-- this.o this.p_o ... : dep
|
|
| 231 | +-- otherwise
|
|
| 232 | +-- this.o ... : dep.hi
|
|
| 233 | +-- this.p_o ... : dep.p_hi
|
|
| 234 | +-- ...
|
|
| 235 | +-- (where .o is $osuf, and the other suffixes come from
|
|
| 236 | +-- the cmdline -s options).
|
|
| 237 | +--
|
|
| 238 | +-- For {-# SOURCE #-} imports the "hi" will be "hi-boot".
|
|
| 239 | + |
|
| 240 | +processDeps _ hsc_env _ _ (CyclicSCC nodes)
|
|
| 241 | + = -- There shouldn't be any cycles; report them
|
|
| 242 | + throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $ cyclicModuleErr nodes
|
|
| 243 | + |
|
| 244 | +processDeps _ hsc_env _ _ (AcyclicSCC (InstantiationNode _uid node))
|
|
| 245 | + = -- There shouldn't be any backpack instantiations; report them as well
|
|
| 246 | + throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $
|
|
| 247 | + mkPlainErrorMsgEnvelope noSrcSpan $
|
|
| 248 | + GhcDriverMessage $ DriverInstantiationNodeInDependencyGeneration node
|
|
| 249 | + |
|
| 250 | +processDeps _dflags _ _ _ (AcyclicSCC (LinkNode {})) = return ()
|
|
| 251 | +processDeps _dflags _ _ _ (AcyclicSCC (UnitNode {})) = return ()
|
|
| 252 | +processDeps _ _ _ _ (AcyclicSCC (ModuleNode _ (ModuleNodeFixed {})))
|
|
| 253 | + -- No dependencies needed for fixed modules (already compiled)
|
|
| 254 | + = return ()
|
|
| 255 | + |
|
| 256 | +processDeps dflags hsc_env excl_mods sinks (AcyclicSCC (ModuleNode _ (ModuleNodeCompile node))) = do
|
|
| 257 | + pp <- preprocessor
|
|
| 258 | + let
|
|
| 259 | + dep_node = mkDepNode pp
|
|
| 260 | + find_deps imps = do
|
|
| 261 | + cpp_deps <- find_cpp_deps
|
|
| 262 | + import_deps <- find_import_deps imps
|
|
| 263 | + pure $ map Right cpp_deps ++ import_deps
|
|
| 264 | + (missing_dep_errs, deps) <- partitionEithers <$> find_deps (ms_imps node)
|
|
| 265 | + |
|
| 266 | + if null missing_dep_errs
|
|
| 267 | + then do
|
|
| 268 | + traverse_ (\ sink -> ds_writeDependency sink dep_node deps) sinks
|
|
| 269 | + else do
|
|
| 270 | + let sec = initSourceErrorContext (hsc_dflags hsc_env)
|
|
| 271 | + throwErrors sec (mkMessages (listToBag missing_dep_errs))
|
|
| 272 | + where
|
|
| 273 | + src_file = msHsFileOsPath node
|
|
| 274 | + mkDepNode preproc =
|
|
| 275 | + DepNode
|
|
| 276 | + { dn_mod = GWIB (ms_mod node) (isBootSummary node)
|
|
| 277 | + , dn_src = src_file
|
|
| 278 | + , dn_obj = msObjFileOsPath node
|
|
| 279 | + , dn_hi = msHiFileOsPath node
|
|
| 280 | + , dn_preprocessing = preproc
|
|
| 281 | + }
|
|
| 282 | + |
|
| 283 | + preprocessor :: IO PreprocessingNode
|
|
| 284 | + preprocessor
|
|
| 285 | + | Just src <- ml_hs_file (ms_location node)
|
|
| 286 | + = runPipeline (hsc_hooks hsc_env) $ do
|
|
| 287 | + let
|
|
| 288 | + (_, suffix) = FilePath.splitExtension src
|
|
| 289 | + lit | Unlit _ <- startPhase suffix = True
|
|
| 290 | + | otherwise = False
|
|
| 291 | + pipe_env = mkPipeEnv StopPreprocess src Nothing NoOutputFile
|
|
| 292 | + unlit_fn <- if lit then use (T_Unlit pipe_env hsc_env src) else pure src
|
|
| 293 | + (dflags1, opts, _, _) <- use (T_FileArgs (hsc_logger hsc_env) (ms_hspp_opts node) unlit_fn)
|
|
| 294 | + let pp = pgm_F dflags1
|
|
| 295 | + pure PreprocessingNode
|
|
| 296 | + { pn_preprocessor = if null pp then global_preprocessor else Just pp
|
|
| 297 | + , pn_options = opts
|
|
| 298 | + }
|
|
| 299 | + | otherwise
|
|
| 300 | + = pure PreprocessingNode
|
|
| 301 | + { pn_preprocessor = global_preprocessor
|
|
| 302 | + , pn_options = []
|
|
| 303 | + }
|
|
| 304 | + |
|
| 305 | + global_preprocessor :: Maybe String
|
|
| 306 | + global_preprocessor
|
|
| 307 | + | let pp = pgm_F dflags
|
|
| 308 | + , not (null pp)
|
|
| 309 | + = Just pp
|
|
| 310 | + | otherwise
|
|
| 311 | + = Nothing
|
|
| 312 | + |
|
| 313 | + -- Emit a dependency for each CPP import
|
|
| 314 | + -- CPP deps are discovered in the module parsing phase by parsing
|
|
| 315 | + -- comment lines left by the preprocessor.
|
|
| 316 | + -- Note that GHC.parseModule may throw an exception if the module
|
|
| 317 | + -- fails to parse, which may not be desirable (see #16616).
|
|
| 318 | + find_cpp_deps :: IO [Dep]
|
|
| 319 | + find_cpp_deps =
|
|
| 320 | + if depIncludeCppDeps dflags
|
|
| 321 | + then do
|
|
| 322 | + session <- Session <$> newIORef hsc_env
|
|
| 323 | + parsedMod <- reflectGhc (GHC.parseModule node) session
|
|
| 324 | + pure (DepCpp . unsafeEncodeUtf <$> GHC.pm_extra_src_files parsedMod)
|
|
| 325 | + else
|
|
| 326 | + pure []
|
|
| 327 | + |
|
| 328 | + -- Emit a dependency for each import
|
|
| 329 | + find_import_deps :: [UnresolvedImport PkgQual] -> IO [Either (MsgEnvelope GhcMessage) Dep]
|
|
| 330 | + find_import_deps idecls =
|
|
| 331 | + sequence
|
|
| 332 | + [ findDependency hsc_env decl
|
|
| 333 | + | decl <- idecls
|
|
| 334 | + , let L _loc mod = ui_mod_name decl
|
|
| 335 | + , not $ mod `UniqSet.elementOfUniqSet` excl_mods
|
|
| 336 | + ]
|
|
| 337 | + |
|
| 338 | +findDependency :: HscEnv
|
|
| 339 | + -> UnresolvedImport PkgQual -- The import to find
|
|
| 340 | + -> IO (Either (MsgEnvelope GhcMessage) Dep) -- Interface file
|
|
| 341 | +findDependency hsc_env imp = do
|
|
| 342 | + -- Find the module; this will be fast because
|
|
| 343 | + -- we've done it once during downsweep.
|
|
| 344 | + r <- resolveImport hsc_env imp
|
|
| 345 | + case r of
|
|
| 346 | + Found loc dep_mod ->
|
|
| 347 | + pure $ Right
|
|
| 348 | + DepHi
|
|
| 349 | + { dep_mod = dep_mod
|
|
| 350 | + , dep_path = ml_hi_file_ospath loc
|
|
| 351 | + , dep_unit = lookupUnitId (hsc_units hsc_env) (moduleUnitId dep_mod)
|
|
| 352 | + , dep_local = isJust (ml_hs_file loc)
|
|
| 353 | + , dep_boot = is_boot
|
|
| 354 | + , dep_level = ui_level imp
|
|
| 355 | + }
|
|
| 356 | + |
|
| 357 | + fail ->
|
|
| 358 | + return $
|
|
| 359 | + Left $
|
|
| 360 | + mkPlainErrorMsgEnvelope srcloc $
|
|
| 361 | + GhcDriverMessage $ DriverInterfaceError $
|
|
| 362 | + (Can'tFindInterface (cannotFindModule hsc_env mod_name fail) (LookingForModule mod_name is_boot))
|
|
| 363 | + where
|
|
| 364 | + L srcloc mod_name = ui_mod_name imp
|
|
| 365 | + is_boot = ui_boot imp
|
|
| 366 | + |
|
| 130 | 367 | -----------------------------------------------------------------
|
| 131 | 368 | --
|
| 132 | 369 | -- beginMkDependHs
|
| ... | ... | @@ -136,6 +373,18 @@ doMkDependModuleGraph dflags module_graph = do |
| 136 | 373 | --
|
| 137 | 374 | -----------------------------------------------------------------
|
| 138 | 375 | |
| 376 | +initFileDepWriter :: Logger -> OsPath -> TmpFs -> DynFlags -> IO DependencyWriter
|
|
| 377 | +initFileDepWriter logger root tmpfs dflags = do
|
|
| 378 | + files <- beginMkDependHS logger tmpfs dflags
|
|
| 379 | + pure DependencyWriter
|
|
| 380 | + { dw_beginWriter = do
|
|
| 381 | + pure $ DepSink $ \ node deps -> do
|
|
| 382 | + writeDependencies (depIncludePkgDeps dflags) root (mkd_tmp_hdl files) suffixes node deps
|
|
| 383 | + , dw_endWriter = endMkDependHS logger files
|
|
| 384 | + }
|
|
| 385 | + where
|
|
| 386 | + suffixes = map unsafeEncodeUtf (depSuffixes dflags)
|
|
| 387 | + |
|
| 139 | 388 | data MkDepFiles
|
| 140 | 389 | = MkDep { mkd_make_file :: FilePath, -- Name of the makefile
|
| 141 | 390 | mkd_make_hdl :: Maybe Handle, -- Handle for the open makefile
|
| ... | ... | @@ -151,7 +400,7 @@ beginMkDependHS logger tmpfs dflags = do |
| 151 | 400 | |
| 152 | 401 | -- open the makefile
|
| 153 | 402 | let makefile = depMakefile dflags
|
| 154 | - exists <- doesFileExist makefile
|
|
| 403 | + exists <- Directory.doesFileExist makefile
|
|
| 155 | 404 | mb_make_hdl <-
|
| 156 | 405 | if not exists
|
| 157 | 406 | then return Nothing
|
| ... | ... | @@ -188,141 +437,53 @@ beginMkDependHS logger tmpfs dflags = do |
| 188 | 437 | return (MkDep { mkd_make_file = makefile, mkd_make_hdl = mb_make_hdl,
|
| 189 | 438 | mkd_tmp_file = tmp_file, mkd_tmp_hdl = tmp_hdl})
|
| 190 | 439 | |
| 440 | +writeDependencies ::
|
|
| 441 | + Bool ->
|
|
| 442 | + OsPath ->
|
|
| 443 | + Handle ->
|
|
| 444 | + [OsString] ->
|
|
| 445 | + -- ^ Suffixes
|
|
| 446 | + DepNode ->
|
|
| 447 | + [Dep] ->
|
|
| 448 | + IO ()
|
|
| 449 | +writeDependencies include_pkgs root hdl suffixes node deps =
|
|
| 450 | + traverse_ write tasks
|
|
| 451 | + where
|
|
| 452 | + tasks = source_dep : boot_dep ++ concatMap import_dep deps
|
|
| 453 | + |
|
| 454 | + -- Emit std dependency of the object(s) on the source file
|
|
| 455 | + -- Something like A.o : A.hs
|
|
| 456 | + source_dep = (obj_files, dn_src)
|
|
| 457 | + |
|
| 458 | + -- add dependency between objects and their corresponding .hi-boot
|
|
| 459 | + -- files if the module has a corresponding .hs-boot file (#14482)
|
|
| 460 | + boot_dep = case gwib_isBoot dn_mod of
|
|
| 461 | + IsBoot -> [([obj], hi) | (obj, hi) <- zip (suffixed (removeBootSuffix dn_obj)) (suffixed dn_hi)]
|
|
| 462 | + NotBoot -> []
|
|
| 463 | + |
|
| 464 | + -- Add one dependency for each suffix;
|
|
| 465 | + -- e.g. A.o : B.hi
|
|
| 466 | + -- A.x_o : B.x_hi
|
|
| 467 | + import_dep = \case
|
|
| 468 | + DepHi {dep_path, dep_unit}
|
|
| 469 | + | isNothing dep_unit || include_pkgs
|
|
| 470 | + -> [([obj], hi) | (obj, hi) <- zip obj_files (suffixed dep_path)]
|
|
| 191 | 471 | |
| 192 | ------------------------------------------------------------------
|
|
| 193 | ---
|
|
| 194 | --- processDeps
|
|
| 195 | ---
|
|
| 196 | ------------------------------------------------------------------
|
|
| 197 | - |
|
| 198 | -processDeps :: DynFlags
|
|
| 199 | - -> HscEnv
|
|
| 200 | - -> [ModuleName]
|
|
| 201 | - -> FilePath
|
|
| 202 | - -> Handle -- Write dependencies to here
|
|
| 203 | - -> SCC ModuleGraphNode
|
|
| 204 | - -> IO ()
|
|
| 205 | --- Write suitable dependencies to handle
|
|
| 206 | --- Always:
|
|
| 207 | --- this.o : this.hs
|
|
| 208 | ---
|
|
| 209 | --- If the dependency is on something other than a .hi file:
|
|
| 210 | --- this.o this.p_o ... : dep
|
|
| 211 | --- otherwise
|
|
| 212 | --- this.o ... : dep.hi
|
|
| 213 | --- this.p_o ... : dep.p_hi
|
|
| 214 | --- ...
|
|
| 215 | --- (where .o is $osuf, and the other suffixes come from
|
|
| 216 | --- the cmdline -s options).
|
|
| 217 | ---
|
|
| 218 | --- For {-# SOURCE #-} imports the "hi" will be "hi-boot".
|
|
| 219 | - |
|
| 220 | -processDeps _ hsc_env _ _ _ (CyclicSCC nodes)
|
|
| 221 | - = -- There shouldn't be any cycles; report them
|
|
| 222 | - throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $ cyclicModuleErr nodes
|
|
| 223 | - |
|
| 224 | -processDeps _ hsc_env _ _ _ (AcyclicSCC (InstantiationNode _uid node))
|
|
| 225 | - = -- There shouldn't be any backpack instantiations; report them as well
|
|
| 226 | - throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $
|
|
| 227 | - mkPlainErrorMsgEnvelope noSrcSpan $
|
|
| 228 | - GhcDriverMessage $ DriverInstantiationNodeInDependencyGeneration node
|
|
| 229 | - |
|
| 230 | -processDeps _dflags _ _ _ _ (AcyclicSCC (LinkNode {})) = return ()
|
|
| 231 | -processDeps _dflags _ _ _ _ (AcyclicSCC (UnitNode {})) = return ()
|
|
| 232 | -processDeps _ _ _ _ _ (AcyclicSCC (ModuleNode _ (ModuleNodeFixed {})))
|
|
| 233 | - -- No dependencies needed for fixed modules (already compiled)
|
|
| 234 | - = return ()
|
|
| 235 | -processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleNodeCompile node)))
|
|
| 236 | - = do { let extra_suffixes = depSuffixes dflags
|
|
| 237 | - include_pkg_deps = depIncludePkgDeps dflags
|
|
| 238 | - src_file = msHsFilePath node
|
|
| 239 | - obj_file = msObjFilePath node
|
|
| 240 | - obj_files = insertSuffixes obj_file extra_suffixes
|
|
| 241 | - |
|
| 242 | - |
|
| 243 | - |
|
| 244 | - -- Emit std dependency of the object(s) on the source file
|
|
| 245 | - -- Something like A.o : A.hs
|
|
| 246 | - ; writeDependency root hdl obj_files src_file
|
|
| 247 | - |
|
| 248 | - -- add dependency between objects and their corresponding .hi-boot
|
|
| 249 | - -- files if the module has a corresponding .hs-boot file (#14482)
|
|
| 250 | - ; when (isBootSummary node == IsBoot) $ do
|
|
| 251 | - let hi_boot = msHiFilePath node
|
|
| 252 | - let obj = unsafeDecodeUtf $ removeBootSuffix (msObjFileOsPath node)
|
|
| 253 | - forM_ extra_suffixes $ \suff -> do
|
|
| 254 | - let way_obj = insertSuffixes obj [suff]
|
|
| 255 | - let way_hi_boot = insertSuffixes hi_boot [suff]
|
|
| 256 | - mapM_ (writeDependency root hdl way_obj) way_hi_boot
|
|
| 257 | - |
|
| 258 | - -- Emit a dependency for each CPP import
|
|
| 259 | - ; when (depIncludeCppDeps dflags) $ do
|
|
| 260 | - -- CPP deps are discovered in the module parsing phase by parsing
|
|
| 261 | - -- comment lines left by the preprocessor.
|
|
| 262 | - -- Note that GHC.parseModule may throw an exception if the module
|
|
| 263 | - -- fails to parse, which may not be desirable (see #16616).
|
|
| 264 | - { session <- Session <$> newIORef hsc_env
|
|
| 265 | - ; parsedMod <- reflectGhc (GHC.parseModule node) session
|
|
| 266 | - ; mapM_ (writeDependency root hdl obj_files)
|
|
| 267 | - (GHC.pm_extra_src_files parsedMod)
|
|
| 268 | - }
|
|
| 269 | - |
|
| 270 | - -- Emit a dependency for each import
|
|
| 271 | - |
|
| 272 | - ; let find_deps imps = sequence
|
|
| 273 | - [ findDependency hsc_env imp include_pkg_deps
|
|
| 274 | - | imp <- imps
|
|
| 275 | - , unLoc (ui_mod_name imp) `notElem` excl_mods
|
|
| 276 | - ]
|
|
| 277 | - |
|
| 278 | - do_imp hi_file = do
|
|
| 279 | - let hi_files = insertSuffixes hi_file extra_suffixes
|
|
| 280 | - write_dep (obj,hi) = writeDependency root hdl [obj] hi
|
|
| 472 | + | otherwise
|
|
| 473 | + -> []
|
|
| 281 | 474 | |
| 282 | - -- Add one dependency for each suffix;
|
|
| 283 | - -- e.g. A.o : B.hi
|
|
| 284 | - -- A.x_o : B.x_hi
|
|
| 285 | - mapM_ write_dep (obj_files `zip` hi_files)
|
|
| 475 | + DepCpp {dep_path} -> [(obj_files, dep_path)]
|
|
| 286 | 476 | |
| 287 | - ; (missing_dep_errs, deps) <- partitionEithers <$> find_deps (ms_imps node)
|
|
| 477 | + write (from, to) = writeDependency root hdl from to
|
|
| 288 | 478 | |
| 289 | - ; if null missing_dep_errs
|
|
| 290 | - then mapM_ (mapM_ do_imp) deps
|
|
| 291 | - else do
|
|
| 292 | - let sec = initSourceErrorContext (hsc_dflags hsc_env)
|
|
| 293 | - throwErrors sec (mkMessages (listToBag missing_dep_errs))
|
|
| 294 | - }
|
|
| 479 | + obj_files = suffixed dn_obj
|
|
| 295 | 480 | |
| 296 | -findDependency :: HscEnv
|
|
| 297 | - -> UnresolvedImport PkgQual -- The import to find
|
|
| 298 | - -> Bool -- Record dependency on package modules
|
|
| 299 | - -> IO (Either (MsgEnvelope GhcMessage) (Maybe FilePath)) -- Interface file
|
|
| 300 | -findDependency hsc_env imp include_pkg_deps = do
|
|
| 301 | - -- Find the module; this will be fast because
|
|
| 302 | - -- we've done it once during downsweep.
|
|
| 303 | - r <- resolveImport hsc_env imp
|
|
| 304 | - case r of
|
|
| 305 | - Found loc _
|
|
| 306 | - -- Home package: just depend on the .hi or hi-boot file
|
|
| 307 | - | isJust (ml_hs_file loc) || include_pkg_deps
|
|
| 308 | - -> return (Right (Just (ml_hi_file loc)))
|
|
| 481 | + suffixed f = insertSuffixes f suffixes
|
|
| 309 | 482 | |
| 310 | - -- Not in this package: we don't need a dependency
|
|
| 311 | - | otherwise
|
|
| 312 | - -> return (Right Nothing)
|
|
| 313 | - |
|
| 314 | - fail ->
|
|
| 315 | - return $
|
|
| 316 | - Left $
|
|
| 317 | - mkPlainErrorMsgEnvelope srcloc $
|
|
| 318 | - GhcDriverMessage $ DriverInterfaceError $
|
|
| 319 | - (Can'tFindInterface (cannotFindModule hsc_env mod_name fail) (LookingForModule mod_name is_boot))
|
|
| 320 | - where
|
|
| 321 | - L srcloc mod_name = ui_mod_name imp
|
|
| 322 | - is_boot = ui_boot imp
|
|
| 483 | + DepNode {dn_src, dn_obj, dn_hi, dn_mod} = node
|
|
| 323 | 484 | |
| 324 | 485 | -----------------------------
|
| 325 | -writeDependency :: FilePath -> Handle -> [FilePath] -> FilePath -> IO ()
|
|
| 486 | +writeDependency :: OsPath -> Handle -> [OsPath] -> OsPath -> IO ()
|
|
| 326 | 487 | -- (writeDependency r h [t1,t2] dep) writes to handle h the dependency
|
| 327 | 488 | -- t1 t2 : dep
|
| 328 | 489 | writeDependency root hdl targets dep
|
| ... | ... | @@ -330,33 +491,30 @@ writeDependency root hdl targets dep |
| 330 | 491 | -- c:/foo/...
|
| 331 | 492 | -- on Windows as make gets confused by the :
|
| 332 | 493 | -- Making relative deps avoids some instances of this.
|
| 333 | - dep' = makeRelative root dep
|
|
| 334 | - forOutput = escapeSpaces . reslash Forwards . normalise
|
|
| 494 | + dep' = OsPath.makeRelative root dep
|
|
| 495 | + forOutput = escapeSpaces . reslash Forwards . unsafeDecodeUtf . OsPath.normalise
|
|
| 335 | 496 | output = unwords (map forOutput targets) ++ " : " ++ forOutput dep'
|
| 336 | 497 | hPutStrLn hdl output
|
| 337 | 498 | |
| 338 | 499 | -----------------------------
|
| 339 | 500 | insertSuffixes
|
| 340 | - :: FilePath -- Original filename; e.g. "foo.o"
|
|
| 341 | - -> [String] -- Suffix prefixes e.g. ["x_", "y_"]
|
|
| 342 | - -> [FilePath] -- Zapped filenames e.g. ["foo.x_o", "foo.y_o"]
|
|
| 501 | + :: OsPath -- Original filename; e.g. "foo.o"
|
|
| 502 | + -> [OsString] -- Suffix prefixes e.g. ["x_", "y_"]
|
|
| 503 | + -> [OsPath] -- Zapped filenames e.g. ["foo.x_o", "foo.y_o"]
|
|
| 343 | 504 | -- Note that the extra bit gets inserted *before* the old suffix
|
| 344 | 505 | -- We assume the old suffix contains no dots, so we know where to
|
| 345 | 506 | -- split it
|
| 346 | 507 | insertSuffixes file_name extras
|
| 347 | - = [ basename <.> (extra ++ suffix) | extra <- extras ]
|
|
| 508 | + = [ basename <.> (extra Monoid.<> suffix) | extra <- extras ]
|
|
| 348 | 509 | where
|
| 349 | - (basename, suffix) = case splitExtension file_name of
|
|
| 510 | + (basename, suffix) = case OsPath.splitExtension file_name of
|
|
| 350 | 511 | -- Drop the "." from the extension
|
| 351 | - (b, s) -> (b, drop 1 s)
|
|
| 512 | + (b, s) -> (b, OsString.drop 1 s)
|
|
| 352 | 513 | |
| 353 | 514 | |
| 354 | 515 | -----------------------------------------------------------------
|
| 355 | ---
|
|
| 356 | --- endMkDependHs
|
|
| 357 | --- Complete the makefile, close the tmp file etc
|
|
| 358 | ---
|
|
| 359 | ------------------------------------------------------------------
|
|
| 516 | +-- endMkDependHs
|
|
| 517 | +-- Complete the makefile, close the tmp file etc
|
|
| 360 | 518 | |
| 361 | 519 | endMkDependHS :: Logger -> MkDepFiles -> IO ()
|
| 362 | 520 | |
| ... | ... | @@ -385,6 +543,277 @@ endMkDependHS logger |
| 385 | 543 | showPass logger "Installing new makefile"
|
| 386 | 544 | SysTools.copyFile tmp_file makefile
|
| 387 | 545 | |
| 546 | +-----------------------------------------------------------------
|
|
| 547 | +--
|
|
| 548 | +-- JSON MkDepends output
|
|
| 549 | +--
|
|
| 550 | +-----------------------------------------------------------------
|
|
| 551 | + |
|
| 552 | +initJsonDepWriter :: FilePath -> DynFlags -> IO DependencyWriter
|
|
| 553 | +initJsonDepWriter output dflags = do
|
|
| 554 | + json_var <- mkJsonOutput output initDepJson
|
|
| 555 | + pure DependencyWriter
|
|
| 556 | + { dw_beginWriter =
|
|
| 557 | + pure $ DepSink $ \ node deps ->
|
|
| 558 | + updateJson json_var (updateDepJson (depIncludePkgDeps dflags) node deps)
|
|
| 559 | + , dw_endWriter =
|
|
| 560 | + writeJsonOutput json_var
|
|
| 561 | + }
|
|
| 562 | + |
|
| 563 | +--------------------------------------------------------------------------------
|
|
| 564 | +-- Output interface for json dumps
|
|
| 565 | + |
|
| 566 | +-- | Resources for a json dump option, used in "GHC.Driver.MakeFile".
|
|
| 567 | +-- The flag @-dep-json@ add an additional output target for dependency
|
|
| 568 | +-- diagnostics.
|
|
| 569 | +data JsonOutput a =
|
|
| 570 | + JsonOutput {
|
|
| 571 | + -- | This ref is updated in @processDeps@ incrementally, using a
|
|
| 572 | + -- flag-specific type.
|
|
| 573 | + json_ref :: IORef a,
|
|
| 574 | + |
|
| 575 | + -- | The output file path specified as argument to the flag.
|
|
| 576 | + json_path :: FilePath
|
|
| 577 | + }
|
|
| 578 | + |
|
| 579 | +-- | TODO: @fendor
|
|
| 580 | +mkJsonOutput ::
|
|
| 581 | + FilePath ->
|
|
| 582 | + IO (IORef a) ->
|
|
| 583 | + IO (JsonOutput a)
|
|
| 584 | +mkJsonOutput json_path mk_ref = do
|
|
| 585 | + json_ref <- mk_ref
|
|
| 586 | + pure JsonOutput {json_ref, json_path}
|
|
| 587 | + |
|
| 588 | +-- | Update the dump data in 'json_ref' if the output target is present.
|
|
| 589 | +updateJson :: JsonOutput a -> (a -> a) -> IO ()
|
|
| 590 | +updateJson JsonOutput {json_ref} f = modifyIORef' json_ref f
|
|
| 591 | + |
|
| 592 | +-- | Write a json object to the flag-dependent file if the output target is
|
|
| 593 | +-- present.
|
|
| 594 | +writeJsonOutput ::
|
|
| 595 | + ToJson a =>
|
|
| 596 | + JsonOutput a ->
|
|
| 597 | + IO ()
|
|
| 598 | +writeJsonOutput JsonOutput {json_ref, json_path} = do
|
|
| 599 | + payload <- readIORef json_ref
|
|
| 600 | + writeJsonFile payload json_path
|
|
| 601 | + |
|
| 602 | +--------------------------------------------------------------------------------
|
|
| 603 | +-- Output helpers
|
|
| 604 | + |
|
| 605 | +writeJsonFile :: ToJson a => a -> FilePath -> IO ()
|
|
| 606 | +writeJsonFile doc p = do
|
|
| 607 | + withAtomicRename p
|
|
| 608 | + $ \tmp -> writeFile tmp $ showSDocUnsafe $ renderJSON $ json doc
|
|
| 609 | + |
|
| 610 | +--------------------------------------------------------------------------------
|
|
| 611 | +-- Payload for -dep-json
|
|
| 612 | + |
|
| 613 | +newtype DPackageId = DPackageId PackageId
|
|
| 614 | + deriving newtype (Eq)
|
|
| 615 | + |
|
| 616 | +instance Ord DPackageId where
|
|
| 617 | + DPackageId (PackageId d1) `compare` DPackageId (PackageId d2) = d1 `lexicalCompareFS` d2
|
|
| 618 | + |
|
| 619 | +data ModuleNodeDeps = ModuleNodeDeps
|
|
| 620 | + { source :: OsPath
|
|
| 621 | + , imports :: ImportDeps
|
|
| 622 | + , cpp :: Set.Set OsPath
|
|
| 623 | + , options :: [String]
|
|
| 624 | + , preprocessor :: Maybe FilePath
|
|
| 625 | + }
|
|
| 626 | + deriving stock (Generic)
|
|
| 627 | + deriving (Semigroup, Monoid) via (Generically ModuleNodeDeps)
|
|
| 628 | + |
|
| 629 | +addImport :: ImportDep -> ModuleNodeDeps -> ModuleNodeDeps
|
|
| 630 | +addImport import_dep mod_node_deps =
|
|
| 631 | + mod_node_deps
|
|
| 632 | + { imports = ImportDeps $ Map.insertWith Set.union uid (Set.singleton import_dep) (getImports $ imports mod_node_deps)
|
|
| 633 | + }
|
|
| 634 | + where
|
|
| 635 | + uid = toUnitId $ moduleUnit $ imp_mod import_dep
|
|
| 636 | + |
|
| 637 | +addCpp :: OsPath -> ModuleNodeDeps -> ModuleNodeDeps
|
|
| 638 | +addCpp p mod_node_deps =
|
|
| 639 | + mod_node_deps
|
|
| 640 | + { cpp = Set.insert p (cpp mod_node_deps)
|
|
| 641 | + }
|
|
| 642 | + |
|
| 643 | +newtype ImportDeps = ImportDeps { getImports :: Map.Map UnitId (Set.Set ImportDep) }
|
|
| 644 | + deriving stock (Generic)
|
|
| 645 | + deriving (Semigroup, Monoid) via (Generically ImportDeps)
|
|
| 646 | + |
|
| 647 | +data ImportDep = ImportDep
|
|
| 648 | + { imp_mod :: Module
|
|
| 649 | + , imp_level :: ImportLevel
|
|
| 650 | + , imp_isBoot :: IsBootInterface
|
|
| 651 | + } deriving (Eq, Ord)
|
|
| 652 | + |
|
| 653 | +mkImportDep :: Module -> ImportLevel -> IsBootInterface -> ImportDep
|
|
| 654 | +mkImportDep modl level isBoot = ImportDep
|
|
| 655 | + { imp_mod = modl
|
|
| 656 | + , imp_level = level
|
|
| 657 | + , imp_isBoot = isBoot
|
|
| 658 | + }
|
|
| 659 | + |
|
| 660 | +data HomeUnitDeps = HomeUnitDeps
|
|
| 661 | + { homeModules :: Map.Map ModuleWithIsBoot ModuleNodeDeps
|
|
| 662 | + }
|
|
| 663 | + deriving stock (Generic)
|
|
| 664 | + deriving (Semigroup, Monoid) via (Generically HomeUnitDeps)
|
|
| 665 | + |
|
| 666 | +data ExtUnitDep = ExtUnitDep
|
|
| 667 | + { extUnitId :: UnitId
|
|
| 668 | + -- ^ The 'UnitId' of a unit. This is assumed to be globally unique.
|
|
| 669 | + , extUnitName :: String
|
|
| 670 | + , extUnitPackageId :: DPackageId
|
|
| 671 | + } deriving (Eq, Ord)
|
|
| 672 | + |
|
| 673 | +data DepJson = DepJson
|
|
| 674 | + { homeUnitDeps :: Map.Map UnitId HomeUnitDeps
|
|
| 675 | + , externalDeps :: Set.Set ExtUnitDep
|
|
| 676 | + }
|
|
| 677 | + |
|
| 678 | +instance ToJson DepJson where
|
|
| 679 | + json (DepJson homeUnits extDeps) =
|
|
| 680 | + JSObject $
|
|
| 681 | + [ homeUnit huid hud
|
|
| 682 | + | (huid, hud) <- Map.toList homeUnits
|
|
| 683 | + ] ++
|
|
| 684 | + [ mkExtDepObj dep
|
|
| 685 | + | dep <- Set.toList extDeps
|
|
| 686 | + ]
|
|
| 687 | + where
|
|
| 688 | + homeUnit uid hud =
|
|
| 689 | + ( unitIdString uid
|
|
| 690 | + , JSObject
|
|
| 691 | + [
|
|
| 692 | + ( "modules"
|
|
| 693 | + , JSObject
|
|
| 694 | + [ (homeUnitModuleKey modl, homeUnitModule deps)
|
|
| 695 | + | (modl, deps) <- Map.toList $ homeModules hud
|
|
| 696 | + ]
|
|
| 697 | + )
|
|
| 698 | + ]
|
|
| 699 | + )
|
|
| 700 | + |
|
| 701 | + homeUnitModuleKey :: ModuleWithIsBoot -> String
|
|
| 702 | + homeUnitModuleKey t = moduleKey (gwib_mod t) (gwib_isBoot t)
|
|
| 703 | + |
|
| 704 | + moduleKey :: Module -> IsBootInterface -> String
|
|
| 705 | + moduleKey t b = moduleNameString (moduleName t) ++ case b of
|
|
| 706 | + IsBoot -> "[boot]"
|
|
| 707 | + NotBoot -> ""
|
|
| 708 | + |
|
| 709 | + homeUnitModule :: ModuleNodeDeps -> JsonDoc
|
|
| 710 | + homeUnitModule ModuleNodeDeps {source, imports, cpp, options, preprocessor} =
|
|
| 711 | + JSObject
|
|
| 712 | + [ ("source", JSString . showOsPath $ normalise source)
|
|
| 713 | + , ("imports", importsObj imports)
|
|
| 714 | + , ("includes", strArray cpp showOsPath)
|
|
| 715 | + , ("options", JSArray $ map JSString options)
|
|
| 716 | + , ("preprocessor", maybe JSNull JSString preprocessor)
|
|
| 717 | + ]
|
|
| 718 | + |
|
| 719 | + importsObj :: ImportDeps -> JsonDoc
|
|
| 720 | + importsObj importDeps = JSArray $ map importObj (Map.toList $ getImports importDeps)
|
|
| 721 | + |
|
| 722 | + importObj :: (UnitId, Set.Set ImportDep) -> JsonDoc
|
|
| 723 | + importObj (uid, importSet) =
|
|
| 724 | + JSObject
|
|
| 725 | + [ (unitIdString uid, array importSet importDepObj )
|
|
| 726 | + ]
|
|
| 727 | + |
|
| 728 | + importDepObj :: ImportDep -> JsonDoc
|
|
| 729 | + importDepObj ImportDep {imp_mod, imp_level, imp_isBoot}
|
|
| 730 | + | NormalLevel <- imp_level = JSString (moduleKey imp_mod imp_isBoot)
|
|
| 731 | + | otherwise = JSObject
|
|
| 732 | + [ ("module", JSString (moduleKey imp_mod imp_isBoot))
|
|
| 733 | + , ("level" , importLevel imp_level)
|
|
| 734 | + ]
|
|
| 735 | + |
|
| 736 | + importLevel :: ImportLevel -> JsonDoc
|
|
| 737 | + importLevel lvl =
|
|
| 738 | + JSString $ case lvl of
|
|
| 739 | + NormalLevel -> "normal"
|
|
| 740 | + SpliceLevel -> "splice"
|
|
| 741 | + QuoteLevel -> "quote"
|
|
| 742 | + |
|
| 743 | + mkExtDepObj :: ExtUnitDep -> (String, JsonDoc)
|
|
| 744 | + mkExtDepObj ExtUnitDep{..} =
|
|
| 745 | + ( unitIdString extUnitId
|
|
| 746 | + , JSObject
|
|
| 747 | + [ ("package-name", JSString extUnitName)
|
|
| 748 | + , ("package-id", JSString $ showPackageId extUnitPackageId)
|
|
| 749 | + ]
|
|
| 750 | + )
|
|
| 751 | + |
|
| 752 | + array values render = JSArray (fmap render (Set.toList values))
|
|
| 753 | + strArray values render = JSArray (fmap (JSString . render) (Set.toList values))
|
|
| 754 | + |
|
| 755 | + showOsPath = unsafeDecodeUtf
|
|
| 756 | + showPackageId (DPackageId (PackageId pid)) = unpackFS pid
|
|
| 757 | + |
|
| 758 | +initDepJson :: IO (IORef DepJson)
|
|
| 759 | +initDepJson = newIORef $ DepJson Map.empty Set.empty
|
|
| 760 | + |
|
| 761 | +insertDepJson :: ModuleWithIsBoot -> ModuleNodeDeps -> Set.Set ExtUnitDep -> DepJson -> DepJson
|
|
| 762 | +insertDepJson target modNode extUnits (DepJson m0 e0) =
|
|
| 763 | + DepJson
|
|
| 764 | + { homeUnitDeps =
|
|
| 765 | + Map.insertWith
|
|
| 766 | + (Semigroup.<>)
|
|
| 767 | + modUnitId
|
|
| 768 | + (HomeUnitDeps $ Map.singleton target modNode)
|
|
| 769 | + m0
|
|
| 770 | + , externalDeps =
|
|
| 771 | + Set.union e0 extUnits
|
|
| 772 | + }
|
|
| 773 | + where
|
|
| 774 | + modUnitId = toUnitId $ moduleUnit $ gwib_mod target
|
|
| 775 | + |
|
| 776 | +updateDepJson :: Bool -> DepNode -> [Dep] -> DepJson -> DepJson
|
|
| 777 | +updateDepJson include_pkgs DepNode {..} deps =
|
|
| 778 | + insertDepJson dn_mod payload externalDeps
|
|
| 779 | + where
|
|
| 780 | + (externalDeps, payload) = foldl' go (Set.empty, initial_node_data) deps
|
|
| 781 | + |
|
| 782 | + initial_node_data =
|
|
| 783 | + ModuleNodeDeps
|
|
| 784 | + { source = dn_src
|
|
| 785 | + , preprocessor = pn_preprocessor dn_preprocessing
|
|
| 786 | + , options = pn_options dn_preprocessing
|
|
| 787 | + , cpp = Set.empty
|
|
| 788 | + , imports = ImportDeps Map.empty
|
|
| 789 | + }
|
|
| 790 | + |
|
| 791 | + go (extDeps, node_data) = \ case
|
|
| 792 | + DepHi {dep_mod, dep_local, dep_unit, dep_boot, dep_level}
|
|
| 793 | + | dep_local
|
|
| 794 | + -> (extDeps, addImport (mkImportDep dep_mod dep_level dep_boot) node_data)
|
|
| 795 | + |
|
| 796 | + | include_pkgs
|
|
| 797 | + , Just unit <- dep_unit
|
|
| 798 | + , let PackageName nameFS = unitPackageName unit
|
|
| 799 | + name = unpackFS nameFS
|
|
| 800 | + withLibName (PackageName c) = name ++ ":" ++ unpackFS c
|
|
| 801 | + lname = maybe name withLibName (unitComponentName unit)
|
|
| 802 | + newExtDep = ExtUnitDep
|
|
| 803 | + { extUnitId = unitId unit
|
|
| 804 | + , extUnitName = lname
|
|
| 805 | + , extUnitPackageId = DPackageId $ unitPackageId unit
|
|
| 806 | + }
|
|
| 807 | + ->
|
|
| 808 | + ( Set.insert newExtDep extDeps
|
|
| 809 | + , addImport (mkImportDep dep_mod dep_level dep_boot) node_data
|
|
| 810 | + )
|
|
| 811 | + |
|
| 812 | + | otherwise
|
|
| 813 | + -> (extDeps, node_data)
|
|
| 814 | + |
|
| 815 | + DepCpp {dep_path} ->
|
|
| 816 | + (extDeps, addCpp dep_path node_data)
|
|
| 388 | 817 | |
| 389 | 818 | -----------------------------------------------------------------
|
| 390 | 819 | -- Module cycles
|
| ... | ... | @@ -820,13 +820,13 @@ preprocessPipeline pipe_env hsc_env input_fn = do |
| 820 | 820 | use (T_Unlit pipe_env hsc_env input_fn)
|
| 821 | 821 | |
| 822 | 822 | |
| 823 | - (dflags1, p_warns1, warns1) <- use (T_FileArgs hsc_env unlit_fn)
|
|
| 823 | + (dflags1, _, p_warns1, warns1) <- use (fileArgsPhase hsc_env unlit_fn)
|
|
| 824 | 824 | let hsc_env1 = hscSetFlags dflags1 hsc_env
|
| 825 | 825 | |
| 826 | 826 | (cpp_fn, hsc_env2)
|
| 827 | 827 | <- runAfterFlag hsc_env1 (Cpp HsSrcFile) (xopt LangExt.Cpp) (unlit_fn, hsc_env1) $ do
|
| 828 | 828 | cpp_fn <- use (T_Cpp pipe_env hsc_env1 unlit_fn)
|
| 829 | - (dflags2, _, _) <- use (T_FileArgs hsc_env1 cpp_fn)
|
|
| 829 | + (dflags2, _, _, _) <- use (fileArgsPhase hsc_env1 cpp_fn)
|
|
| 830 | 830 | let hsc_env2 = hscSetFlags dflags2 hsc_env1
|
| 831 | 831 | return (cpp_fn, hsc_env2)
|
| 832 | 832 | |
| ... | ... | @@ -841,7 +841,8 @@ preprocessPipeline pipe_env hsc_env input_fn = do |
| 841 | 841 | then return (dflags1, p_warns1, warns1)
|
| 842 | 842 | else do
|
| 843 | 843 | -- Reparse with original hsc_env so that we don't get duplicated options
|
| 844 | - use (T_FileArgs hsc_env pp_fn)
|
|
| 844 | + (dflagsPP, _, p_warns3, warns3) <- use (fileArgsPhase hsc_env pp_fn)
|
|
| 845 | + pure (dflagsPP, p_warns3, warns3)
|
|
| 845 | 846 | |
| 846 | 847 | let print_config = initPrintConfig dflags3
|
| 847 | 848 | liftIO (printOrThrowDiagnostics (hsc_logger hsc_env) print_config (initDiagOpts dflags3) (GhcPsMessage <$> p_warns3))
|
| ... | ... | @@ -865,6 +866,9 @@ preprocessPipeline pipe_env hsc_env input_fn = do |
| 865 | 866 | runAfter phase def
|
| 866 | 867 | $ phaseIfFlag hsc_env flag def action
|
| 867 | 868 | |
| 869 | + fileArgsPhase env fn =
|
|
| 870 | + T_FileArgs (hsc_logger env) (hsc_dflags env) fn
|
|
| 871 | + |
|
| 868 | 872 | -- | The complete compilation pipeline, from start to finish
|
| 869 | 873 | fullPipeline :: P m => PipeEnv -> HscEnv -> FilePath -> HscSource -> m (ModIface, RecompLinkables)
|
| 870 | 874 | fullPipeline pipe_env hsc_env pp_fn src_flavour = do
|
| ... | ... | @@ -104,7 +104,7 @@ runPhase :: TPhase out -> IO out |
| 104 | 104 | runPhase (T_Unlit pipe_env hsc_env inp_path) = do
|
| 105 | 105 | out_path <- phaseOutputFilenameNew (Cpp HsSrcFile) pipe_env hsc_env Nothing
|
| 106 | 106 | runUnlitPhase hsc_env inp_path out_path
|
| 107 | -runPhase (T_FileArgs hsc_env inp_path) = getFileArgs hsc_env inp_path
|
|
| 107 | +runPhase (T_FileArgs logger dflags inp_path) = getFileArgsNoHsc logger dflags inp_path
|
|
| 108 | 108 | runPhase (T_Cpp pipe_env hsc_env inp_path) = do
|
| 109 | 109 | out_path <- phaseOutputFilenameNew (HsPp HsSrcFile) pipe_env hsc_env Nothing
|
| 110 | 110 | runCppPhase hsc_env inp_path out_path
|
| ... | ... | @@ -620,17 +620,21 @@ runUnlitPhase hsc_env input_fn output_fn = do |
| 620 | 620 | |
| 621 | 621 | return output_fn
|
| 622 | 622 | |
| 623 | -getFileArgs :: HscEnv -> FilePath -> IO ((DynFlags, Messages PsMessage, Messages DriverMessage))
|
|
| 623 | +getFileArgs :: HscEnv -> FilePath -> IO ((DynFlags, [String], Messages PsMessage, Messages DriverMessage))
|
|
| 624 | 624 | getFileArgs hsc_env input_fn = do
|
| 625 | 625 | let dflags0 = hsc_dflags hsc_env
|
| 626 | 626 | logger = hsc_logger hsc_env
|
| 627 | - parser_opts = initParserOpts dflags0
|
|
| 627 | + getFileArgsNoHsc logger dflags0 input_fn
|
|
| 628 | + |
|
| 629 | +getFileArgsNoHsc :: Logger -> DynFlags -> FilePath -> IO ((DynFlags, [String], Messages PsMessage, Messages DriverMessage))
|
|
| 630 | +getFileArgsNoHsc logger dflags0 input_fn = do
|
|
| 631 | + let parser_opts = initParserOpts dflags0
|
|
| 628 | 632 | sec = initSourceErrorContext dflags0
|
| 629 | 633 | (warns0, src_opts) <- getOptionsFromFile parser_opts sec (supportedLanguagePragmas dflags0) input_fn
|
| 630 | 634 | (dflags1, unhandled_flags, warns)
|
| 631 | 635 | <- parseDynamicFilePragma logger dflags0 src_opts
|
| 632 | 636 | checkProcessArgsResult dflags0 unhandled_flags
|
| 633 | - return (dflags1, warns0, warns)
|
|
| 637 | + return (dflags1, map unLoc src_opts, warns0, warns)
|
|
| 634 | 638 | |
| 635 | 639 | runCppPhase :: HscEnv -> FilePath -> FilePath -> IO FilePath
|
| 636 | 640 | runCppPhase hsc_env input_fn output_fn = do
|
| ... | ... | @@ -13,6 +13,7 @@ import GHC.Driver.Errors.Types |
| 13 | 13 | import GHC.Fingerprint.Type
|
| 14 | 14 | import GHC.Unit.Module.Location ( ModLocation )
|
| 15 | 15 | import GHC.Unit.Module.ModIface
|
| 16 | +import GHC.Utils.Logger
|
|
| 16 | 17 | import GHC.Driver.Phases
|
| 17 | 18 | |
| 18 | 19 | import Language.Haskell.Syntax.Module.Name ( ModuleName )
|
| ... | ... | @@ -25,7 +26,7 @@ import GHC.Unit.Home.ModInfo |
| 25 | 26 | -- phase if the inputs have been modified.
|
| 26 | 27 | data TPhase res where
|
| 27 | 28 | T_Unlit :: PipeEnv -> HscEnv -> FilePath -> TPhase FilePath
|
| 28 | - T_FileArgs :: HscEnv -> FilePath -> TPhase (DynFlags, Messages PsMessage, Messages DriverMessage)
|
|
| 29 | + T_FileArgs :: Logger -> DynFlags -> FilePath -> TPhase ((DynFlags, [String], Messages PsMessage, Messages DriverMessage))
|
|
| 29 | 30 | T_Cpp :: PipeEnv -> HscEnv -> FilePath -> TPhase FilePath
|
| 30 | 31 | T_HsPp :: PipeEnv -> HscEnv -> FilePath -> FilePath -> TPhase FilePath
|
| 31 | 32 | T_HscRecomp :: PipeEnv -> HscEnv -> FilePath -> HscSource -> TPhase (HscEnv, ModSummary, HscRecompStatus)
|
| ... | ... | @@ -791,6 +791,12 @@ addOptCmmP f = alterToolSettings $ \s -> s |
| 791 | 791 | setDepMakefile :: FilePath -> DynFlags -> DynFlags
|
| 792 | 792 | setDepMakefile f d = d { depMakefile = f }
|
| 793 | 793 | |
| 794 | +setDepJson :: FilePath -> DynFlags -> DynFlags
|
|
| 795 | +setDepJson f d = d { depJson = Just f }
|
|
| 796 | + |
|
| 797 | +unsetDepJson :: DynFlags -> DynFlags
|
|
| 798 | +unsetDepJson d = d { depJson = Nothing }
|
|
| 799 | + |
|
| 794 | 800 | setDepIncludeCppDeps :: Bool -> DynFlags -> DynFlags
|
| 795 | 801 | setDepIncludeCppDeps b d = d { depIncludeCppDeps = b }
|
| 796 | 802 | |
| ... | ... | @@ -1261,6 +1267,8 @@ dynamic_flags_deps = [ |
| 1261 | 1267 | -------- ghc -M -----------------------------------------------------
|
| 1262 | 1268 | , make_ord_flag defGhcFlag "dep-suffix" (hasArg addDepSuffix)
|
| 1263 | 1269 | , make_ord_flag defGhcFlag "dep-makefile" (hasArg setDepMakefile)
|
| 1270 | + , make_ord_flag defGhcFlag "dep-json" (hasArg setDepJson)
|
|
| 1271 | + , make_ord_flag defGhcFlag "no-dep-json" (noArg unsetDepJson)
|
|
| 1264 | 1272 | , make_ord_flag defGhcFlag "include-cpp-deps"
|
| 1265 | 1273 | (noArg (setDepIncludeCppDeps True))
|
| 1266 | 1274 | , make_ord_flag defGhcFlag "include-pkg-deps"
|
| ... | ... | @@ -1503,6 +1503,23 @@ generation are: |
| 1503 | 1503 | ``.depend`` and then ``include`` the file ``.depend`` into
|
| 1504 | 1504 | ``Makefile``.
|
| 1505 | 1505 | |
| 1506 | +.. ghc-flag:: -dep-json ⟨file⟩
|
|
| 1507 | + :shortdesc: Also emit ⟨file⟩ as a JSON file containing dependencies
|
|
| 1508 | + :type: dynamic
|
|
| 1509 | + :reverse: -no-dep-json
|
|
| 1510 | + :category: redirect-output
|
|
| 1511 | + |
|
| 1512 | + In addition to the makefile, also emit ⟨file⟩ as a JSON file
|
|
| 1513 | + containing the same dependencies info, so it can be parsed by
|
|
| 1514 | + external build systems. The JSON file contains a single object,
|
|
| 1515 | + mapping each target to a list of dependencies.
|
|
| 1516 | + In addition to the makefile, each module's payload will contain the
|
|
| 1517 | + values of ``OPTIONS`` and ``LANGUAGE`` pragmas of the source
|
|
| 1518 | + file, so it can be parsed by external build systems. Each ``LANGUAGE``
|
|
| 1519 | + pragma is represented as an option as well, e.g.
|
|
| 1520 | + ``{-# LANGUAGE TemplateHaskell #-}`` is represented as
|
|
| 1521 | + ``"-XTemplateHaskell"``.
|
|
| 1522 | + |
|
| 1506 | 1523 | .. ghc-flag:: -dep-suffix ⟨suffix⟩
|
| 1507 | 1524 | :shortdesc: Make dependencies that declare that files with suffix
|
| 1508 | 1525 | ``.⟨suf⟩⟨osuf⟩`` depend on interface files with suffix ``.⟨suf⟩hi``
|
| ... | ... | @@ -20,6 +20,7 @@ from pathlib import Path, PurePath |
| 20 | 20 | import collections
|
| 21 | 21 | import collections.abc
|
| 22 | 22 | import subprocess
|
| 23 | +import json
|
|
| 23 | 24 | |
| 24 | 25 | from testglobals import config, ghc_env, default_testopts, brokens, t, \
|
| 25 | 26 | TestRun, TestResult, TestOptions, PerfMetric
|
| ... | ... | @@ -3265,6 +3266,34 @@ def normalise_asm( s: str ) -> str: |
| 3265 | 3266 | out.append(ins[0])
|
| 3266 | 3267 | return '\n'.join(out)
|
| 3267 | 3268 | |
| 3269 | +def normalise_dep_json(s: str) -> str:
|
|
| 3270 | + """
|
|
| 3271 | + Normalise the json output of `ghc -M -dep-json output.json`
|
|
| 3272 | + """
|
|
| 3273 | + |
|
| 3274 | + def normalise_includes(j):
|
|
| 3275 | + # Only normalise proper json objects.
|
|
| 3276 | + # Strings might be parsed as json strings, but we that's not what we are looking for
|
|
| 3277 | + if not isinstance(j, dict):
|
|
| 3278 | + return j
|
|
| 3279 | + for unit in j.values():
|
|
| 3280 | + for module in unit.get("modules", {}).values():
|
|
| 3281 | + rewritten = [
|
|
| 3282 | + "<absolute-path>/" + p.rsplit("/", 1)[-1] if p.startswith("/") else p
|
|
| 3283 | + for p in module["includes"]
|
|
| 3284 | + ]
|
|
| 3285 | + # we sort to make sure this never
|
|
| 3286 | + module["includes"] = sorted(rewritten)
|
|
| 3287 | + return j
|
|
| 3288 | + |
|
| 3289 | + output = ""
|
|
| 3290 | + try:
|
|
| 3291 | + normalised_dep_json = normalise_includes(json.loads(s))
|
|
| 3292 | + output = json.dumps(normalised_dep_json, indent=2, sort_keys=True, ensure_ascii=False)
|
|
| 3293 | + except json.JSONDecodeError:
|
|
| 3294 | + output = line
|
|
| 3295 | + return output
|
|
| 3296 | + |
|
| 3268 | 3297 | def safe_print(s: str) -> None:
|
| 3269 | 3298 | s2 = s.encode(sys.stdout.encoding, errors='replace').decode(sys.stdout.encoding)
|
| 3270 | 3299 | print(s2)
|
| 1 | +{-# language Strict #-}
|
|
| 2 | +{-# language CPP #-}
|
|
| 3 | +{-# options_ghc -fexpose-all-unfoldings #-}
|
|
| 4 | +module A where
|
|
| 5 | + |
|
| 6 | +#include "foo.h"
|
|
| 7 | +import {-# source #-} C |
| 1 | +module C where
|
|
| 2 | + |
|
| 3 | +import A
|
|
| 4 | +import Data.Set
|
|
| 5 | + |
|
| 6 | +data C = C |
| 1 | +module C where
|
|
| 2 | + |
|
| 3 | +import E
|
|
| 4 | + |
|
| 5 | +data C |
| 1 | +module D where
|
|
| 2 | + |
|
| 3 | +import B
|
|
| 4 | +import C |
| 1 | +module E where
|
|
| 2 | + |
|
| 3 | +import Language.Haskell.TH.Syntax
|
|
| 4 | +import Dep
|
|
| 5 | +import DepPublic
|
|
| 6 | + |
|
| 7 | +e :: Q Exp
|
|
| 8 | +e = lift (5 :: Integer)
|
|
| 9 | + |
|
| 10 | +edep :: ()
|
|
| 11 | +edep = dep
|
|
| 12 | + |
|
| 13 | +edepPub :: ()
|
|
| 14 | +edepPub = depPub |
| 1 | +TOP=../../..
|
|
| 2 | +include $(TOP)/mk/boilerplate.mk
|
|
| 3 | +include $(TOP)/mk/test.mk
|
|
| 4 | + |
|
| 5 | + |
|
| 6 | +PKGCONF_LOCAL=./db.package.conf
|
|
| 7 | +GHC_PKG_LOCAL='$(GHC_PKG)' --no-user-package-db -f $(PKGCONF_LOCAL)
|
|
| 8 | + |
|
| 9 | +T24384_prep:
|
|
| 10 | + rm -r $(PKGCONF_LOCAL) || true
|
|
| 11 | + $(GHC_PKG_LOCAL) init $(PKGCONF_LOCAL) 2>&1 >/dev/null
|
|
| 12 | + |
|
| 13 | + cd dep-internal && \
|
|
| 14 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
|
|
| 15 | + -v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-internal-1-XXX \
|
|
| 16 | + -package base \
|
|
| 17 | + -i. DepInternal
|
|
| 18 | + $(GHC_PKG_LOCAL) register --force dep-internal/dep-internal.pkg 2>&1 >/dev/null
|
|
| 19 | + |
|
| 20 | + cd dep-public && \
|
|
| 21 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
|
|
| 22 | + -v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-public-1-XXX \
|
|
| 23 | + -package base \
|
|
| 24 | + -i. DepPublic
|
|
| 25 | + $(GHC_PKG_LOCAL) register --force dep-public/dep-public.pkg 2>&1 >/dev/null
|
|
| 26 | + |
|
| 27 | + cd dep && \
|
|
| 28 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
|
|
| 29 | + -v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-1-XXX \
|
|
| 30 | + -package-db ../$(PKGCONF_LOCAL) -package-id dep-internal-1-XXX \
|
|
| 31 | + -i. Dep
|
|
| 32 | + $(GHC_PKG_LOCAL) register --force dep/dep.pkg 2>&1 >/dev/null
|
|
| 33 | + |
|
| 34 | +T24384a: T24384_prep
|
|
| 35 | + '$(TEST_HC)' -M -dep-makefile T24384a.Makefile -include-pkg-deps -include-cpp-deps \
|
|
| 36 | + -hide-all-packages -package base -package containers -package template-haskell \
|
|
| 37 | + -package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
|
|
| 38 | + A.hs lib/B.hs C.hs D.hs E.hs
|
|
| 39 | + |
|
| 40 | + cat T24384a.Makefile
|
|
| 41 | + |
|
| 42 | +T24384b: T24384_prep
|
|
| 43 | + '$(TEST_HC)' -M -dep-json dep.json -include-pkg-deps -include-cpp-deps \
|
|
| 44 | + -hide-all-packages -package base -package containers -package template-haskell \
|
|
| 45 | + -package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
|
|
| 46 | + A.hs lib/B.hs C.hs D.hs E.hs
|
|
| 47 | + |
|
| 48 | + cat dep.json
|
|
| 49 | + |
|
| 50 | +T24384c: T24384_prep
|
|
| 51 | + '$(TEST_HC)' -M -dep-json dep.json \
|
|
| 52 | + -hide-all-packages -package base -package containers -package template-haskell \
|
|
| 53 | + -package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
|
|
| 54 | + A.hs lib/B.hs C.hs D.hs E.hs
|
|
| 55 | + |
|
| 56 | + cat dep.json |
| 1 | +# DO NOT DELETE: Beginning of Haskell dependencies
|
|
| 2 | +E.o : E.hs
|
|
| 3 | +E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 4 | +E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 5 | +E.o : dep-public/outdir/DepPublic.hi
|
|
| 6 | +E.o : dep/outdir/Dep.hi
|
|
| 7 | +E.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/template-haskell-2.25.0.0-inplace/Language/Haskell/TH/Syntax.hi
|
|
| 8 | +C.o-boot : C.hs-boot
|
|
| 9 | +C.o : C.hi-boot
|
|
| 10 | +C.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 11 | +C.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 12 | +C.o-boot : E.hi
|
|
| 13 | +A.o : A.hs
|
|
| 14 | +A.o : foo.h
|
|
| 15 | +A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/rts-1.0.3/include/ghcversion.h
|
|
| 16 | +A.o : /usr/include/stdc-predef.h
|
|
| 17 | +A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 18 | +A.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 19 | +A.o : C.hi-boot
|
|
| 20 | +C.o : C.hs
|
|
| 21 | +C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 22 | +C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 23 | +C.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/containers-0.8-inplace/Data/Set.hi
|
|
| 24 | +C.o : A.hi
|
|
| 25 | +lib/B.o-boot : lib/B.hs-boot
|
|
| 26 | +lib/B.o : lib/B.hi-boot
|
|
| 27 | +lib/B.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 28 | +lib/B.o-boot : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 29 | +lib/B.o-boot : A.hi
|
|
| 30 | +lib/B.o : lib/B.hs
|
|
| 31 | +lib/B.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 32 | +lib/B.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 33 | +lib/B.o : A.hi
|
|
| 34 | +D.o : D.hs
|
|
| 35 | +D.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/Prelude.hi
|
|
| 36 | +D.o : /home/hugin/Documents/haskell/ghc-homes/ghc-dep-json/_build/stage1/lib/../lib/x86_64-linux-ghc-10.1.20260917-inplace/base-4.23.0.0-inplace/GHC/Essentials.hi
|
|
| 37 | +D.o : C.hi
|
|
| 38 | +D.o : lib/B.hi
|
|
| 39 | +# DO NOT DELETE: End of Haskell dependencies |
| 1 | +{
|
|
| 2 | + "base-<VERSION>-<HASH>": {
|
|
| 3 | + "package-id": "base-<VERSION>-<HASH>",
|
|
| 4 | + "package-name": "base"
|
|
| 5 | + },
|
|
| 6 | + "containers-<VERSION>-<HASH>": {
|
|
| 7 | + "package-id": "containers-<VERSION>-<HASH>",
|
|
| 8 | + "package-name": "containers"
|
|
| 9 | + },
|
|
| 10 | + "dep-1-XXX": {
|
|
| 11 | + "package-id": "dep-1",
|
|
| 12 | + "package-name": "dep"
|
|
| 13 | + },
|
|
| 14 | + "dep-public-1-XXX": {
|
|
| 15 | + "package-id": "dep-public-1",
|
|
| 16 | + "package-name": "dep-public"
|
|
| 17 | + },
|
|
| 18 | + "main": {
|
|
| 19 | + "modules": {
|
|
| 20 | + "A": {
|
|
| 21 | + "imports": [
|
|
| 22 | + {
|
|
| 23 | + "base-<VERSION>-<HASH>": [
|
|
| 24 | + "GHC.Essentials",
|
|
| 25 | + "Prelude"
|
|
| 26 | + ]
|
|
| 27 | + },
|
|
| 28 | + {
|
|
| 29 | + "main": [
|
|
| 30 | + "C[boot]"
|
|
| 31 | + ]
|
|
| 32 | + }
|
|
| 33 | + ],
|
|
| 34 | + "includes": [
|
|
| 35 | + "<absolute-path>/ghcversion.h",
|
|
| 36 | + "<absolute-path>/stdc-predef.h",
|
|
| 37 | + "foo.h"
|
|
| 38 | + ],
|
|
| 39 | + "options": [
|
|
| 40 | + "-XStrict",
|
|
| 41 | + "-XCPP",
|
|
| 42 | + "-fexpose-all-unfoldings"
|
|
| 43 | + ],
|
|
| 44 | + "preprocessor": null,
|
|
| 45 | + "source": "A.hs"
|
|
| 46 | + },
|
|
| 47 | + "B": {
|
|
| 48 | + "imports": [
|
|
| 49 | + {
|
|
| 50 | + "base-<VERSION>-<HASH>": [
|
|
| 51 | + "GHC.Essentials",
|
|
| 52 | + "Prelude"
|
|
| 53 | + ]
|
|
| 54 | + },
|
|
| 55 | + {
|
|
| 56 | + "main": [
|
|
| 57 | + "A"
|
|
| 58 | + ]
|
|
| 59 | + }
|
|
| 60 | + ],
|
|
| 61 | + "includes": [],
|
|
| 62 | + "options": [
|
|
| 63 | + "-F",
|
|
| 64 | + "-pgmF",
|
|
| 65 | + "./preproc.sh"
|
|
| 66 | + ],
|
|
| 67 | + "preprocessor": "./preproc.sh",
|
|
| 68 | + "source": "lib/B.hs"
|
|
| 69 | + },
|
|
| 70 | + "B[boot]": {
|
|
| 71 | + "imports": [
|
|
| 72 | + {
|
|
| 73 | + "base-<VERSION>-<HASH>": [
|
|
| 74 | + "GHC.Essentials",
|
|
| 75 | + "Prelude"
|
|
| 76 | + ]
|
|
| 77 | + },
|
|
| 78 | + {
|
|
| 79 | + "main": [
|
|
| 80 | + "A"
|
|
| 81 | + ]
|
|
| 82 | + }
|
|
| 83 | + ],
|
|
| 84 | + "includes": [],
|
|
| 85 | + "options": [
|
|
| 86 | + "-F",
|
|
| 87 | + "-pgmF",
|
|
| 88 | + "./preproc.sh"
|
|
| 89 | + ],
|
|
| 90 | + "preprocessor": "./preproc.sh",
|
|
| 91 | + "source": "lib/B.hs-boot"
|
|
| 92 | + },
|
|
| 93 | + "C": {
|
|
| 94 | + "imports": [
|
|
| 95 | + {
|
|
| 96 | + "base-<VERSION>-<HASH>": [
|
|
| 97 | + "GHC.Essentials",
|
|
| 98 | + "Prelude"
|
|
| 99 | + ]
|
|
| 100 | + },
|
|
| 101 | + {
|
|
| 102 | + "containers-<VERSION>-<HASH>": [
|
|
| 103 | + "Data.Set"
|
|
| 104 | + ]
|
|
| 105 | + },
|
|
| 106 | + {
|
|
| 107 | + "main": [
|
|
| 108 | + "A"
|
|
| 109 | + ]
|
|
| 110 | + }
|
|
| 111 | + ],
|
|
| 112 | + "includes": [],
|
|
| 113 | + "options": [],
|
|
| 114 | + "preprocessor": null,
|
|
| 115 | + "source": "C.hs"
|
|
| 116 | + },
|
|
| 117 | + "C[boot]": {
|
|
| 118 | + "imports": [
|
|
| 119 | + {
|
|
| 120 | + "base-<VERSION>-<HASH>": [
|
|
| 121 | + "GHC.Essentials",
|
|
| 122 | + "Prelude"
|
|
| 123 | + ]
|
|
| 124 | + },
|
|
| 125 | + {
|
|
| 126 | + "main": [
|
|
| 127 | + "E"
|
|
| 128 | + ]
|
|
| 129 | + }
|
|
| 130 | + ],
|
|
| 131 | + "includes": [],
|
|
| 132 | + "options": [],
|
|
| 133 | + "preprocessor": null,
|
|
| 134 | + "source": "C.hs-boot"
|
|
| 135 | + },
|
|
| 136 | + "D": {
|
|
| 137 | + "imports": [
|
|
| 138 | + {
|
|
| 139 | + "base-<VERSION>-<HASH>": [
|
|
| 140 | + "GHC.Essentials",
|
|
| 141 | + "Prelude"
|
|
| 142 | + ]
|
|
| 143 | + },
|
|
| 144 | + {
|
|
| 145 | + "main": [
|
|
| 146 | + "B",
|
|
| 147 | + "C"
|
|
| 148 | + ]
|
|
| 149 | + }
|
|
| 150 | + ],
|
|
| 151 | + "includes": [],
|
|
| 152 | + "options": [],
|
|
| 153 | + "preprocessor": null,
|
|
| 154 | + "source": "D.hs"
|
|
| 155 | + },
|
|
| 156 | + "E": {
|
|
| 157 | + "imports": [
|
|
| 158 | + {
|
|
| 159 | + "base-<VERSION>-<HASH>": [
|
|
| 160 | + "GHC.Essentials",
|
|
| 161 | + "Prelude"
|
|
| 162 | + ]
|
|
| 163 | + },
|
|
| 164 | + {
|
|
| 165 | + "dep-1-XXX": [
|
|
| 166 | + "Dep"
|
|
| 167 | + ]
|
|
| 168 | + },
|
|
| 169 | + {
|
|
| 170 | + "dep-public-1-XXX": [
|
|
| 171 | + "DepPublic"
|
|
| 172 | + ]
|
|
| 173 | + },
|
|
| 174 | + {
|
|
| 175 | + "template-haskell-<VERSION>-<HASH>": [
|
|
| 176 | + "Language.Haskell.TH.Syntax"
|
|
| 177 | + ]
|
|
| 178 | + }
|
|
| 179 | + ],
|
|
| 180 | + "includes": [],
|
|
| 181 | + "options": [],
|
|
| 182 | + "preprocessor": null,
|
|
| 183 | + "source": "E.hs"
|
|
| 184 | + }
|
|
| 185 | + }
|
|
| 186 | + },
|
|
| 187 | + "template-haskell-<VERSION>-<HASH>": {
|
|
| 188 | + "package-id": "template-haskell-<VERSION>-<HASH>",
|
|
| 189 | + "package-name": "template-haskell"
|
|
| 190 | + }
|
|
| 191 | +} |
| 1 | +{
|
|
| 2 | + "base-<VERSION>-<HASH>": {
|
|
| 3 | + "package-id": "base-<VERSION>-<HASH>",
|
|
| 4 | + "package-name": "base"
|
|
| 5 | + },
|
|
| 6 | + "containers-<VERSION>-<HASH>": {
|
|
| 7 | + "package-id": "containers-<VERSION>-<HASH>",
|
|
| 8 | + "package-name": "containers"
|
|
| 9 | + },
|
|
| 10 | + "dep-1-XXX": {
|
|
| 11 | + "package-id": "dep-1",
|
|
| 12 | + "package-name": "dep"
|
|
| 13 | + },
|
|
| 14 | + "dep-public-1-XXX": {
|
|
| 15 | + "package-id": "dep-public-1",
|
|
| 16 | + "package-name": "dep-public"
|
|
| 17 | + },
|
|
| 18 | + "main": {
|
|
| 19 | + "modules": {
|
|
| 20 | + "A": {
|
|
| 21 | + "imports": [
|
|
| 22 | + {
|
|
| 23 | + "base-<VERSION>-<HASH>": [
|
|
| 24 | + "GHC.Essentials",
|
|
| 25 | + "Prelude"
|
|
| 26 | + ]
|
|
| 27 | + },
|
|
| 28 | + {
|
|
| 29 | + "main": [
|
|
| 30 | + "C[boot]"
|
|
| 31 | + ]
|
|
| 32 | + }
|
|
| 33 | + ],
|
|
| 34 | + "includes": [
|
|
| 35 | + "<absolute-path>/ghcversion.h",
|
|
| 36 | + "<absolute-path>/stdc-predef.h",
|
|
| 37 | + "foo.h"
|
|
| 38 | + ],
|
|
| 39 | + "options": [
|
|
| 40 | + "-XStrict",
|
|
| 41 | + "-XCPP",
|
|
| 42 | + "-fexpose-all-unfoldings"
|
|
| 43 | + ],
|
|
| 44 | + "preprocessor": null,
|
|
| 45 | + "source": "A.hs"
|
|
| 46 | + },
|
|
| 47 | + "B": {
|
|
| 48 | + "imports": [
|
|
| 49 | + {
|
|
| 50 | + "base-<VERSION>-<HASH>": [
|
|
| 51 | + "GHC.Essentials",
|
|
| 52 | + "Prelude"
|
|
| 53 | + ]
|
|
| 54 | + },
|
|
| 55 | + {
|
|
| 56 | + "main": [
|
|
| 57 | + "A"
|
|
| 58 | + ]
|
|
| 59 | + }
|
|
| 60 | + ],
|
|
| 61 | + "includes": [],
|
|
| 62 | + "options": [
|
|
| 63 | + "-F",
|
|
| 64 | + "-pgmF",
|
|
| 65 | + "./preproc.sh"
|
|
| 66 | + ],
|
|
| 67 | + "preprocessor": "./preproc.sh",
|
|
| 68 | + "source": "lib/B.hs"
|
|
| 69 | + },
|
|
| 70 | + "B[boot]": {
|
|
| 71 | + "imports": [
|
|
| 72 | + {
|
|
| 73 | + "base-<VERSION>-<HASH>": [
|
|
| 74 | + "GHC.Essentials",
|
|
| 75 | + "Prelude"
|
|
| 76 | + ]
|
|
| 77 | + },
|
|
| 78 | + {
|
|
| 79 | + "main": [
|
|
| 80 | + "A"
|
|
| 81 | + ]
|
|
| 82 | + }
|
|
| 83 | + ],
|
|
| 84 | + "includes": [],
|
|
| 85 | + "options": [
|
|
| 86 | + "-F",
|
|
| 87 | + "-pgmF",
|
|
| 88 | + "./preproc.sh"
|
|
| 89 | + ],
|
|
| 90 | + "preprocessor": "./preproc.sh",
|
|
| 91 | + "source": "lib/B.hs-boot"
|
|
| 92 | + },
|
|
| 93 | + "C": {
|
|
| 94 | + "imports": [
|
|
| 95 | + {
|
|
| 96 | + "base-<VERSION>-<HASH>": [
|
|
| 97 | + "GHC.Essentials",
|
|
| 98 | + "Prelude"
|
|
| 99 | + ]
|
|
| 100 | + },
|
|
| 101 | + {
|
|
| 102 | + "containers-<VERSION>-<HASH>": [
|
|
| 103 | + "Data.Set"
|
|
| 104 | + ]
|
|
| 105 | + },
|
|
| 106 | + {
|
|
| 107 | + "main": [
|
|
| 108 | + "A"
|
|
| 109 | + ]
|
|
| 110 | + }
|
|
| 111 | + ],
|
|
| 112 | + "includes": [],
|
|
| 113 | + "options": [],
|
|
| 114 | + "preprocessor": null,
|
|
| 115 | + "source": "C.hs"
|
|
| 116 | + },
|
|
| 117 | + "C[boot]": {
|
|
| 118 | + "imports": [
|
|
| 119 | + {
|
|
| 120 | + "base-<VERSION>-<HASH>": [
|
|
| 121 | + "GHC.Essentials",
|
|
| 122 | + "Prelude"
|
|
| 123 | + ]
|
|
| 124 | + },
|
|
| 125 | + {
|
|
| 126 | + "main": [
|
|
| 127 | + "E"
|
|
| 128 | + ]
|
|
| 129 | + }
|
|
| 130 | + ],
|
|
| 131 | + "includes": [],
|
|
| 132 | + "options": [],
|
|
| 133 | + "preprocessor": null,
|
|
| 134 | + "source": "C.hs-boot"
|
|
| 135 | + },
|
|
| 136 | + "D": {
|
|
| 137 | + "imports": [
|
|
| 138 | + {
|
|
| 139 | + "base-<VERSION>-<HASH>": [
|
|
| 140 | + "GHC.Essentials",
|
|
| 141 | + "Prelude"
|
|
| 142 | + ]
|
|
| 143 | + },
|
|
| 144 | + {
|
|
| 145 | + "main": [
|
|
| 146 | + "B",
|
|
| 147 | + "C"
|
|
| 148 | + ]
|
|
| 149 | + }
|
|
| 150 | + ],
|
|
| 151 | + "includes": [],
|
|
| 152 | + "options": [],
|
|
| 153 | + "preprocessor": null,
|
|
| 154 | + "source": "D.hs"
|
|
| 155 | + },
|
|
| 156 | + "E": {
|
|
| 157 | + "imports": [
|
|
| 158 | + {
|
|
| 159 | + "base-<VERSION>-<HASH>": [
|
|
| 160 | + "GHC.Essentials",
|
|
| 161 | + "Prelude"
|
|
| 162 | + ]
|
|
| 163 | + },
|
|
| 164 | + {
|
|
| 165 | + "dep-1-XXX": [
|
|
| 166 | + "Dep"
|
|
| 167 | + ]
|
|
| 168 | + },
|
|
| 169 | + {
|
|
| 170 | + "dep-public-1-XXX": [
|
|
| 171 | + "DepPublic"
|
|
| 172 | + ]
|
|
| 173 | + },
|
|
| 174 | + {
|
|
| 175 | + "template-haskell-<VERSION>-<HASH>": [
|
|
| 176 | + "Language.Haskell.TH.Syntax"
|
|
| 177 | + ]
|
|
| 178 | + }
|
|
| 179 | + ],
|
|
| 180 | + "includes": [],
|
|
| 181 | + "options": [],
|
|
| 182 | + "preprocessor": null,
|
|
| 183 | + "source": "E.hs"
|
|
| 184 | + }
|
|
| 185 | + }
|
|
| 186 | + },
|
|
| 187 | + "template-haskell-<VERSION>-<HASH>": {
|
|
| 188 | + "package-id": "template-haskell-<VERSION>-<HASH>",
|
|
| 189 | + "package-name": "template-haskell"
|
|
| 190 | + }
|
|
| 191 | +} |
| 1 | +{
|
|
| 2 | + "main": {
|
|
| 3 | + "modules": {
|
|
| 4 | + "A": {
|
|
| 5 | + "imports": [
|
|
| 6 | + {
|
|
| 7 | + "main": [
|
|
| 8 | + "C[boot]"
|
|
| 9 | + ]
|
|
| 10 | + }
|
|
| 11 | + ],
|
|
| 12 | + "includes": [],
|
|
| 13 | + "options": [
|
|
| 14 | + "-XStrict",
|
|
| 15 | + "-XCPP",
|
|
| 16 | + "-fexpose-all-unfoldings"
|
|
| 17 | + ],
|
|
| 18 | + "preprocessor": null,
|
|
| 19 | + "source": "A.hs"
|
|
| 20 | + },
|
|
| 21 | + "B": {
|
|
| 22 | + "imports": [
|
|
| 23 | + {
|
|
| 24 | + "main": [
|
|
| 25 | + "A"
|
|
| 26 | + ]
|
|
| 27 | + }
|
|
| 28 | + ],
|
|
| 29 | + "includes": [],
|
|
| 30 | + "options": [
|
|
| 31 | + "-F",
|
|
| 32 | + "-pgmF",
|
|
| 33 | + "./preproc.sh"
|
|
| 34 | + ],
|
|
| 35 | + "preprocessor": "./preproc.sh",
|
|
| 36 | + "source": "lib/B.hs"
|
|
| 37 | + },
|
|
| 38 | + "B[boot]": {
|
|
| 39 | + "imports": [
|
|
| 40 | + {
|
|
| 41 | + "main": [
|
|
| 42 | + "A"
|
|
| 43 | + ]
|
|
| 44 | + }
|
|
| 45 | + ],
|
|
| 46 | + "includes": [],
|
|
| 47 | + "options": [
|
|
| 48 | + "-F",
|
|
| 49 | + "-pgmF",
|
|
| 50 | + "./preproc.sh"
|
|
| 51 | + ],
|
|
| 52 | + "preprocessor": "./preproc.sh",
|
|
| 53 | + "source": "lib/B.hs-boot"
|
|
| 54 | + },
|
|
| 55 | + "C": {
|
|
| 56 | + "imports": [
|
|
| 57 | + {
|
|
| 58 | + "main": [
|
|
| 59 | + "A"
|
|
| 60 | + ]
|
|
| 61 | + }
|
|
| 62 | + ],
|
|
| 63 | + "includes": [],
|
|
| 64 | + "options": [],
|
|
| 65 | + "preprocessor": null,
|
|
| 66 | + "source": "C.hs"
|
|
| 67 | + },
|
|
| 68 | + "C[boot]": {
|
|
| 69 | + "imports": [
|
|
| 70 | + {
|
|
| 71 | + "main": [
|
|
| 72 | + "E"
|
|
| 73 | + ]
|
|
| 74 | + }
|
|
| 75 | + ],
|
|
| 76 | + "includes": [],
|
|
| 77 | + "options": [],
|
|
| 78 | + "preprocessor": null,
|
|
| 79 | + "source": "C.hs-boot"
|
|
| 80 | + },
|
|
| 81 | + "D": {
|
|
| 82 | + "imports": [
|
|
| 83 | + {
|
|
| 84 | + "main": [
|
|
| 85 | + "B",
|
|
| 86 | + "C"
|
|
| 87 | + ]
|
|
| 88 | + }
|
|
| 89 | + ],
|
|
| 90 | + "includes": [],
|
|
| 91 | + "options": [],
|
|
| 92 | + "preprocessor": null,
|
|
| 93 | + "source": "D.hs"
|
|
| 94 | + },
|
|
| 95 | + "E": {
|
|
| 96 | + "imports": [],
|
|
| 97 | + "includes": [],
|
|
| 98 | + "options": [],
|
|
| 99 | + "preprocessor": null,
|
|
| 100 | + "source": "E.hs"
|
|
| 101 | + }
|
|
| 102 | + }
|
|
| 103 | + }
|
|
| 104 | +} |
| 1 | +test_extras = extra_files(
|
|
| 2 | + ['A.hs', 'lib/', 'C.hs', 'C.hs-boot', 'D.hs', 'E.hs',
|
|
| 3 | + 'foo.h',
|
|
| 4 | + 'dep', 'dep-internal', 'dep-public',
|
|
| 5 | + 'preproc.sh'
|
|
| 6 | + ])
|
|
| 7 | + |
|
| 8 | +normalisers = [ normalise_version('base', 'containers', 'template-haskell')
|
|
| 9 | + , normalise_slashes
|
|
| 10 | + , normalise_fun(normalise_dep_json)
|
|
| 11 | + ]
|
|
| 12 | + |
|
| 13 | +test('T24384a', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), *normalisers ], makefile_test, [])
|
|
| 14 | +test('T24384b', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), *normalisers ], makefile_test, [])
|
|
| 15 | +test('T24384c', [ test_extras, pre_cmd('$MAKE -s --no-print-directory T24384_prep'), *normalisers ], makefile_test, []) |
| 1 | +module DepInternal where
|
|
| 2 | +depInt :: ()
|
|
| 3 | +depInt = () |
| 1 | +name: dep-internal
|
|
| 2 | +version: 1
|
|
| 3 | +id: dep-internal-1-XXX
|
|
| 4 | +key: dep-internal-1-XXX
|
|
| 5 | +visibility: public
|
|
| 6 | +abi: inplace
|
|
| 7 | +exposed-modules: DepInternal
|
|
| 8 | +depends:
|
|
| 9 | +import-dirs: ${pkgroot}/dep-internal/outdir
|
|
| 10 | +library-dirs: ${pkgroot}/dep-internal/outdir
|
|
| 11 | +include-dirs: |
| 1 | +module DepPublic where
|
|
| 2 | +depPub :: ()
|
|
| 3 | +depPub = () |
| 1 | +name: dep-public
|
|
| 2 | +version: 1
|
|
| 3 | +id: dep-public-1-XXX
|
|
| 4 | +key: dep-public-1-XXX
|
|
| 5 | +visibility: public
|
|
| 6 | +abi: inplace
|
|
| 7 | +exposed-modules: DepPublic
|
|
| 8 | +depends:
|
|
| 9 | +import-dirs: ${pkgroot}/dep-public/outdir
|
|
| 10 | +library-dirs: ${pkgroot}/dep-public/outdir
|
|
| 11 | +include-dirs: |
| 1 | +module Dep where
|
|
| 2 | +import DepInternal
|
|
| 3 | +dep :: ()
|
|
| 4 | +dep = depInt |
| 1 | +name: dep
|
|
| 2 | +version: 1
|
|
| 3 | +id: dep-1-XXX
|
|
| 4 | +key: dep-1-XXX
|
|
| 5 | +visibility: public
|
|
| 6 | +abi: inplace
|
|
| 7 | +exposed-modules: Dep
|
|
| 8 | +depends: dep-internal-1-XXX
|
|
| 9 | +import-dirs: ${pkgroot}/dep/outdir
|
|
| 10 | +library-dirs: ${pkgroot}/dep/outdir
|
|
| 11 | +include-dirs: |
| 1 | +#!/usr/bin/env bash
|
|
| 2 | +set -euo pipefail
|
|
| 3 | + |
|
| 4 | +# Packages whose ids are rewritten to <pkg>-<VERSION>-<HASH>
|
|
| 5 | +pkgs='base|containers|template-haskell'
|
|
| 6 | + |
|
| 7 | +usage() {
|
|
| 8 | + cat <<EOF
|
|
| 9 | +Usage: $(basename "$0") FILE
|
|
| 10 | + |
|
| 11 | +Format one of the test -dep-json output file with jq and normalise it:
|
|
| 12 | + - absolute paths in "includes" become <absolute-path>/<filename>,
|
|
| 13 | + and the "includes" lists are sorted
|
|
| 14 | + - ids of the packages ${packages[*]}
|
|
| 15 | + (e.g. base-4.23.0.0-inplace) become <pkg>-<VERSION>-<HASH>
|
|
| 16 | + |
|
| 17 | +Writes the output to FILE
|
|
| 18 | +EOF
|
|
| 19 | +}
|
|
| 20 | + |
|
| 21 | +case "${1:-}" in -h|--help) usage; exit 0 ;; esac
|
|
| 22 | +[ $# -eq 1 ] || { usage >&2; exit 1; }
|
|
| 23 | + |
|
| 24 | +# Escape regex metacharacters (and the / delimiter) for sed
|
|
| 25 | +esc() { sed 's/[][\.*^$+?(){}|/]/\\&/g'; }
|
|
| 26 | + |
|
| 27 | +json=$(jq --sort-keys '
|
|
| 28 | + (.. | objects | select(has("includes")) | .includes) |=
|
|
| 29 | + (map(if startswith("/") then "<absolute-path>/" + (split("/") | last) else . end) | sort)
|
|
| 30 | +' "$1")
|
|
| 31 | + |
|
| 32 | +tmp=$(mktemp "$1.XXXXXX")
|
|
| 33 | +trap 'rm -f "$tmp"' EXIT
|
|
| 34 | +sed -E "s/($pkgs)-[0-9.]+(-[0-9a-zA-Z+]+)?(-[0-9a-zA-Z]+)?/\\1-<VERSION>-<HASH>/g" <<<"$json" > "$tmp"
|
|
| 35 | +mv "$tmp" "$1" |
| 1 | +{-# options_ghc -F -pgmF ./preproc.sh #-}
|
|
| 2 | +module B where |
| 1 | +{-# options_ghc -F -pgmF ./preproc.sh #-}
|
|
| 2 | +module B where |
| 1 | +#!/usr/bin/env bash
|
|
| 2 | + |
|
| 3 | +sed '/preproc/d' $2 > $3
|
|
| 4 | +echo 'import A' >> $3 |