Hassan Al-Awwadi pushed to branch wip/haanss/depdir at Glasgow Haskell Compiler / GHC
Commits:
-
01d3154e
by Wen Kokke at 2025-07-10T17:06:36+01:00
-
ac259c48
by Wen Kokke at 2025-07-10T17:06:38+01:00
-
2b4db9ba
by Pi Delport at 2025-07-11T16:40:52-04:00
-
0bfcaf03
by Hassan Al-Awwadi at 2025-07-14T18:54:33+02:00
25 changed files:
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Iface/Make.hs
- compiler/GHC/Iface/Recomp.hs
- compiler/GHC/Iface/Recomp/Types.hs
- compiler/GHC/Tc/Gen/Splice.hs
- compiler/GHC/Tc/Types.hs
- compiler/GHC/Tc/Utils/Monad.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Unit/Finder/Types.hs
- compiler/GHC/Unit/Module/Deps.hs
- docs/users_guide/9.14.1-notes.rst
- docs/users_guide/eventlog-formats.rst
- docs/users_guide/separate_compilation.rst
- libraries/ghc-internal/src/GHC/Internal/Base.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/TH.hs
- libraries/template-haskell/Language/Haskell/TH/Syntax.hs
- testsuite/.gitignore
- testsuite/tests/interface-stability/template-haskell-exports.stdout
- testsuite/tests/th/Makefile
- + testsuite/tests/th/TH_Depends_Dir.hs
- + testsuite/tests/th/TH_Depends_Dir.stdout
- + testsuite/tests/th/TH_Depends_Dir_External.hs
- testsuite/tests/th/all.T
Changes:
| ... | ... | @@ -75,14 +75,15 @@ data UsageConfig = UsageConfig |
| 75 | 75 | |
| 76 | 76 | mkUsageInfo :: UsageConfig -> Plugins -> FinderCache -> UnitEnv
|
| 77 | 77 | -> Module -> ImportedMods -> [ImportUserSpec] -> NameSet
|
| 78 | - -> [FilePath] -> [(Module, Fingerprint)] -> [Linkable] -> PkgsLoaded
|
|
| 78 | + -> [FilePath] -> [FilePath] -> [(Module, Fingerprint)] -> [Linkable] -> PkgsLoaded
|
|
| 79 | 79 | -> IfG [Usage]
|
| 80 | 80 | mkUsageInfo uc plugins fc unit_env
|
| 81 | 81 | this_mod dir_imp_mods imp_decls used_names
|
| 82 | - dependent_files merged needed_links needed_pkgs
|
|
| 82 | + dependent_files dependent_dirs merged needed_links needed_pkgs
|
|
| 83 | 83 | = do
|
| 84 | 84 | eps <- liftIO $ readIORef (euc_eps (ue_eps unit_env))
|
| 85 | - hashes <- liftIO $ mapM getFileHash dependent_files
|
|
| 85 | + file_hashes <- liftIO $ mapM getFileHash dependent_files
|
|
| 86 | + dirs_hashes <- liftIO $ mapM getDirHash dependent_dirs
|
|
| 86 | 87 | let hu = ue_unsafeHomeUnit unit_env
|
| 87 | 88 | hug = ue_home_unit_graph unit_env
|
| 88 | 89 | -- Dependencies on object files due to TH and plugins
|
| ... | ... | @@ -93,7 +94,11 @@ mkUsageInfo uc plugins fc unit_env |
| 93 | 94 | let usages = mod_usages ++ [ UsageFile { usg_file_path = mkFastString f
|
| 94 | 95 | , usg_file_hash = hash
|
| 95 | 96 | , usg_file_label = Nothing }
|
| 96 | - | (f, hash) <- zip dependent_files hashes ]
|
|
| 97 | + | (f, hash) <- zip dependent_files file_hashes ]
|
|
| 98 | + ++ [ UsageDirectory { usg_dir_path = mkFastString d
|
|
| 99 | + , usg_dir_hash = hash
|
|
| 100 | + , usg_dir_label = Nothing }
|
|
| 101 | + | (d, hash) <- zip dependent_dirs dirs_hashes]
|
|
| 97 | 102 | ++ [ UsageMergedRequirement
|
| 98 | 103 | { usg_mod = mod,
|
| 99 | 104 | usg_mod_hash = hash
|
| ... | ... | @@ -269,6 +269,7 @@ mkRecompUsageInfo hsc_env tc_result = do |
| 269 | 269 | else do
|
| 270 | 270 | let used_names = mkUsedNames tc_result
|
| 271 | 271 | dep_files <- (readIORef (tcg_dependent_files tc_result))
|
| 272 | + dep_dirs <- (readIORef (tcg_dependent_dirs tc_result))
|
|
| 272 | 273 | (needed_links, needed_pkgs) <- readIORef (tcg_th_needed_deps tc_result)
|
| 273 | 274 | let uc = initUsageConfig hsc_env
|
| 274 | 275 | plugins = hsc_plugins hsc_env
|
| ... | ... | @@ -289,6 +290,7 @@ mkRecompUsageInfo hsc_env tc_result = do |
| 289 | 290 | (tcg_import_decls tc_result)
|
| 290 | 291 | used_names
|
| 291 | 292 | dep_files
|
| 293 | + dep_dirs
|
|
| 292 | 294 | (tcg_merged tc_result)
|
| 293 | 295 | needed_links
|
| 294 | 296 | needed_pkgs
|
| ... | ... | @@ -194,6 +194,7 @@ data RecompReason |
| 194 | 194 | | ModuleChangedRaw ModuleName
|
| 195 | 195 | | ModuleChangedIface ModuleName
|
| 196 | 196 | | FileChanged FilePath
|
| 197 | + | DirChanged FilePath
|
|
| 197 | 198 | | CustomReason String
|
| 198 | 199 | | FlagsChanged
|
| 199 | 200 | | LinkFlagsChanged
|
| ... | ... | @@ -230,6 +231,7 @@ instance Outputable RecompReason where |
| 230 | 231 | ModuleRemoved (_st, _uid, m) -> ppr m <+> text "removed"
|
| 231 | 232 | ModuleAdded (_st, _uid, m) -> ppr m <+> text "added"
|
| 232 | 233 | FileChanged fp -> text fp <+> text "changed"
|
| 234 | + DirChanged dp -> text dp <+> text "changed"
|
|
| 233 | 235 | CustomReason s -> text s
|
| 234 | 236 | FlagsChanged -> text "Flags changed"
|
| 235 | 237 | LinkFlagsChanged -> text "Flags changed"
|
| ... | ... | @@ -815,6 +817,22 @@ checkModUsage fc UsageFile{ usg_file_path = file, |
| 815 | 817 | then \e -> pprTrace "UsageFile" (text (show e)) $ return recomp
|
| 816 | 818 | else \_ -> return recomp -- if we can't find the file, just recompile, don't fail
|
| 817 | 819 | |
| 820 | +checkModUsage fc UsageDirectory{ usg_dir_path = dir,
|
|
| 821 | + usg_dir_hash = old_hash,
|
|
| 822 | + usg_dir_label = mlabel } =
|
|
| 823 | + liftIO $
|
|
| 824 | + handleIO handler $ do
|
|
| 825 | + new_hash <- lookupDirCache fc $ unpackFS dir
|
|
| 826 | + if (old_hash /= new_hash)
|
|
| 827 | + then return recomp
|
|
| 828 | + else return UpToDate
|
|
| 829 | + where
|
|
| 830 | + reason = DirChanged $ unpackFS dir
|
|
| 831 | + recomp = needsRecompileBecause $ fromMaybe reason $ fmap CustomReason mlabel
|
|
| 832 | + handler = if debugIsOn
|
|
| 833 | + then \e -> pprTrace "UsageDirectory" (text (show e)) $ return recomp
|
|
| 834 | + else \_ -> return recomp -- if we can't find the dir, just recompile, don't fail
|
|
| 835 | + |
|
| 818 | 836 | -- | We are importing a module whose exports have changed.
|
| 819 | 837 | -- Does this require recompilation?
|
| 820 | 838 | --
|
| ... | ... | @@ -140,6 +140,10 @@ pprUsage usage@UsageFile{} |
| 140 | 140 | = hsep [text "addDependentFile",
|
| 141 | 141 | doubleQuotes (ftext (usg_file_path usage)),
|
| 142 | 142 | ppr (usg_file_hash usage)]
|
| 143 | +pprUsage usage@UsageDirectory{}
|
|
| 144 | + = hsep [text "AddDependentDirectory",
|
|
| 145 | + doubleQuotes (ftext (usg_dir_path usage)),
|
|
| 146 | + ppr (usg_dir_hash usage)]
|
|
| 143 | 147 | pprUsage usage@UsageMergedRequirement{}
|
| 144 | 148 | = hsep [text "merged", ppr (usg_mod usage), ppr (usg_mod_hash usage)]
|
| 145 | 149 | pprUsage usage@UsageHomeModuleInterface{}
|
| ... | ... | @@ -173,8 +173,6 @@ import GHC.Parser.HaddockLex (lexHsDoc) |
| 173 | 173 | import GHC.Parser (parseIdentifier)
|
| 174 | 174 | import GHC.Rename.Doc (rnHsDoc)
|
| 175 | 175 | |
| 176 | - |
|
| 177 | - |
|
| 178 | 176 | {-
|
| 179 | 177 | Note [Template Haskell state diagram]
|
| 180 | 178 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -1524,6 +1522,11 @@ instance TH.Quasi TcM where |
| 1524 | 1522 | dep_files <- readTcRef ref
|
| 1525 | 1523 | writeTcRef ref (fp:dep_files)
|
| 1526 | 1524 | |
| 1525 | + qAddDependentDirectory dp = do
|
|
| 1526 | + ref <- fmap tcg_dependent_dirs getGblEnv
|
|
| 1527 | + dep_dirs <- readTcRef ref
|
|
| 1528 | + writeTcRef ref (dp:dep_dirs)
|
|
| 1529 | + |
|
| 1527 | 1530 | qAddTempFile suffix = do
|
| 1528 | 1531 | dflags <- getDynFlags
|
| 1529 | 1532 | logger <- getLogger
|
| ... | ... | @@ -1928,6 +1931,7 @@ handleTHMessage msg = case msg of |
| 1928 | 1931 | ReifyConStrictness nm -> wrapTHResult $ TH.qReifyConStrictness nm
|
| 1929 | 1932 | GetPackageRoot -> wrapTHResult $ TH.qGetPackageRoot
|
| 1930 | 1933 | AddDependentFile f -> wrapTHResult $ TH.qAddDependentFile f
|
| 1934 | + AddDependentDirectory d -> wrapTHResult $ TH.qAddDependentDirectory d
|
|
| 1931 | 1935 | AddTempFile s -> wrapTHResult $ TH.qAddTempFile s
|
| 1932 | 1936 | AddModFinalizer r -> do
|
| 1933 | 1937 | interp <- hscInterp <$> getTopEnv
|
| ... | ... | @@ -603,6 +603,7 @@ data TcGblEnv |
| 603 | 603 | -- decls.
|
| 604 | 604 | |
| 605 | 605 | tcg_dependent_files :: TcRef [FilePath], -- ^ dependencies from addDependentFile
|
| 606 | + tcg_dependent_dirs :: TcRef [FilePath], -- ^ dependencies from addDependentDirectory
|
|
| 606 | 607 | |
| 607 | 608 | tcg_th_topdecls :: TcRef [LHsDecl GhcPs],
|
| 608 | 609 | -- ^ Top-level declarations from addTopDecls
|
| ... | ... | @@ -55,7 +55,7 @@ module GHC.Tc.Utils.Monad( |
| 55 | 55 | getRdrEnvs, getImports,
|
| 56 | 56 | getFixityEnv, extendFixityEnv,
|
| 57 | 57 | getDeclaredDefaultTys,
|
| 58 | - addDependentFiles,
|
|
| 58 | + addDependentFiles, addDependentDirectories,
|
|
| 59 | 59 | |
| 60 | 60 | -- * Error management
|
| 61 | 61 | getSrcSpanM, setSrcSpan, setSrcSpanA, addLocM,
|
| ... | ... | @@ -274,6 +274,7 @@ initTc hsc_env hsc_src keep_rn_syntax mod loc do_this |
| 274 | 274 | let { type_env_var = hsc_type_env_vars hsc_env };
|
| 275 | 275 | |
| 276 | 276 | dependent_files_var <- newIORef [] ;
|
| 277 | + dependent_dirs_var <- newIORef [] ;
|
|
| 277 | 278 | static_wc_var <- newIORef emptyWC ;
|
| 278 | 279 | cc_st_var <- newIORef newCostCentreState ;
|
| 279 | 280 | th_topdecls_var <- newIORef [] ;
|
| ... | ... | @@ -369,6 +370,7 @@ initTc hsc_env hsc_src keep_rn_syntax mod loc do_this |
| 369 | 370 | tcg_safe_infer = infer_var,
|
| 370 | 371 | tcg_safe_infer_reasons = infer_reasons_var,
|
| 371 | 372 | tcg_dependent_files = dependent_files_var,
|
| 373 | + tcg_dependent_dirs = dependent_dirs_var,
|
|
| 372 | 374 | tcg_tc_plugin_solvers = [],
|
| 373 | 375 | tcg_tc_plugin_rewriters = emptyUFM,
|
| 374 | 376 | tcg_defaulting_plugins = [],
|
| ... | ... | @@ -957,6 +959,12 @@ addDependentFiles fs = do |
| 957 | 959 | dep_files <- readTcRef ref
|
| 958 | 960 | writeTcRef ref (fs ++ dep_files)
|
| 959 | 961 | |
| 962 | +addDependentDirectories :: [FilePath] -> TcRn ()
|
|
| 963 | +addDependentDirectories ds = do
|
|
| 964 | + ref <- fmap tcg_dependent_dirs getGblEnv
|
|
| 965 | + dep_dirs <- readTcRef ref
|
|
| 966 | + writeTcRef ref (ds ++ dep_dirs)
|
|
| 967 | + |
|
| 960 | 968 | {-
|
| 961 | 969 | ************************************************************************
|
| 962 | 970 | * *
|
| ... | ... | @@ -31,6 +31,9 @@ module GHC.Unit.Finder ( |
| 31 | 31 | |
| 32 | 32 | findObjectLinkableMaybe,
|
| 33 | 33 | findObjectLinkable,
|
| 34 | + |
|
| 35 | + -- important that GHC.HsToCore.Usage uses the same hashing method for usage dirs as is used here.
|
|
| 36 | + getDirHash,
|
|
| 34 | 37 | ) where
|
| 35 | 38 | |
| 36 | 39 | import GHC.Prelude
|
| ... | ... | @@ -68,7 +71,9 @@ import qualified Data.Map as M |
| 68 | 71 | import GHC.Driver.Env
|
| 69 | 72 | import GHC.Driver.Config.Finder
|
| 70 | 73 | import qualified Data.Set as Set
|
| 74 | +import qualified Data.List as L(sort)
|
|
| 71 | 75 | import Data.List.NonEmpty ( NonEmpty (..) )
|
| 76 | +import qualified System.Directory as SD
|
|
| 72 | 77 | import qualified System.OsPath as OsPath
|
| 73 | 78 | import qualified Data.List.NonEmpty as NE
|
| 74 | 79 | |
| ... | ... | @@ -107,10 +112,12 @@ initFinderCache :: IO FinderCache |
| 107 | 112 | initFinderCache = do
|
| 108 | 113 | mod_cache <- newIORef emptyInstalledModuleEnv
|
| 109 | 114 | file_cache <- newIORef M.empty
|
| 115 | + dir_cache <- newIORef M.empty
|
|
| 110 | 116 | let flushFinderCaches :: UnitEnv -> IO ()
|
| 111 | 117 | flushFinderCaches ue = do
|
| 112 | 118 | atomicModifyIORef' mod_cache $ \fm -> (filterInstalledModuleEnv is_ext fm, ())
|
| 113 | 119 | atomicModifyIORef' file_cache $ \_ -> (M.empty, ())
|
| 120 | + atomicModifyIORef' dir_cache $ \_ -> (M.empty, ())
|
|
| 114 | 121 | where
|
| 115 | 122 | is_ext mod _ = not (isUnitEnvInstalledModule ue mod)
|
| 116 | 123 | |
| ... | ... | @@ -137,8 +144,29 @@ initFinderCache = do |
| 137 | 144 | atomicModifyIORef' file_cache $ \c -> (M.insert key hash c, ())
|
| 138 | 145 | return hash
|
| 139 | 146 | Just fp -> return fp
|
| 147 | + lookupDirCache :: FilePath -> IO Fingerprint
|
|
| 148 | + lookupDirCache key = do
|
|
| 149 | + c <- readIORef dir_cache
|
|
| 150 | + case M.lookup key c of
|
|
| 151 | + Nothing -> do
|
|
| 152 | + hash <- getDirHash key
|
|
| 153 | + atomicModifyIORef' dir_cache $ \c -> (M.insert key hash c, ())
|
|
| 154 | + return hash
|
|
| 155 | + Just fp -> return fp
|
|
| 140 | 156 | return FinderCache{..}
|
| 141 | 157 | |
| 158 | +-- | This function computes a shallow hash of a directory, so really just what files and directories are directly inside it.
|
|
| 159 | +-- It does not look at the contents of the files, or the contents of the directories it contains.
|
|
| 160 | +getDirHash :: FilePath -> IO Fingerprint
|
|
| 161 | +getDirHash dir = do
|
|
| 162 | + contents <- SD.listDirectory dir
|
|
| 163 | + -- The documentation of Fingerprints describes this as an easy naive implementation
|
|
| 164 | + -- I wonder if we should do something more sophisticated here?
|
|
| 165 | + let hashes = fingerprintString <$> contents
|
|
| 166 | + let s_hashes = L.sort hashes
|
|
| 167 | + let hash = fingerprintFingerprints s_hashes
|
|
| 168 | + return hash
|
|
| 169 | + |
|
| 142 | 170 | -- -----------------------------------------------------------------------------
|
| 143 | 171 | -- The three external entry points
|
| 144 | 172 |
| ... | ... | @@ -37,6 +37,7 @@ data FinderCache = FinderCache { flushFinderCaches :: UnitEnv -> IO () |
| 37 | 37 | , lookupFileCache :: FilePath -> IO Fingerprint
|
| 38 | 38 | -- ^ Look for the hash of a file in the cache. This should add it to the
|
| 39 | 39 | -- cache. If the file doesn't exist, raise an IOException.
|
| 40 | + , lookupDirCache :: FilePath -> IO Fingerprint
|
|
| 40 | 41 | }
|
| 41 | 42 | |
| 42 | 43 | data InstalledFindResult
|
| ... | ... | @@ -357,6 +357,23 @@ data Usage |
| 357 | 357 | -- contents don't change. This previously lead to odd
|
| 358 | 358 | -- recompilation behaviors; see #8114
|
| 359 | 359 | }
|
| 360 | + | UsageDirectory {
|
|
| 361 | + usg_dir_path :: FastString,
|
|
| 362 | + -- ^ External dir dependency. From TH addDependentFile.
|
|
| 363 | + -- Should be absolute.
|
|
| 364 | + usg_dir_hash :: Fingerprint,
|
|
| 365 | + -- ^ 'Fingerprint' of the directories contents.
|
|
| 366 | + |
|
| 367 | + usg_dir_label :: Maybe String
|
|
| 368 | + -- ^ An optional string which is used in recompilation messages if
|
|
| 369 | + -- dir in question has changed.
|
|
| 370 | + |
|
| 371 | + -- Note: We do a very shallow check indeed, just what the contents of
|
|
| 372 | + -- the directory are, aka what files and directories are within it.
|
|
| 373 | + -- If those files/directories have their own contents changed...
|
|
| 374 | + -- We won't spot it here, better recursive add them to your usage
|
|
| 375 | + -- seperately.
|
|
| 376 | + }
|
|
| 360 | 377 | | UsageHomeModuleInterface {
|
| 361 | 378 | usg_mod_name :: ModuleName
|
| 362 | 379 | -- ^ Name of the module
|
| ... | ... | @@ -395,6 +412,7 @@ instance NFData Usage where |
| 395 | 412 | rnf (UsagePackageModule mod hash safe) = rnf mod `seq` rnf hash `seq` rnf safe `seq` ()
|
| 396 | 413 | rnf (UsageHomeModule mod uid hash entities exports safe) = rnf mod `seq` rnf uid `seq` rnf hash `seq` rnf entities `seq` rnf exports `seq` rnf safe `seq` ()
|
| 397 | 414 | rnf (UsageFile file hash label) = rnf file `seq` rnf hash `seq` rnf label `seq` ()
|
| 415 | + rnf (UsageDirectory dir hash label) = rnf dir `seq` rnf hash `seq` rnf label `seq` ()
|
|
| 398 | 416 | rnf (UsageMergedRequirement mod hash) = rnf mod `seq` rnf hash `seq` ()
|
| 399 | 417 | rnf (UsageHomeModuleInterface mod uid hash) = rnf mod `seq` rnf uid `seq` rnf hash `seq` ()
|
| 400 | 418 | |
| ... | ... | @@ -431,6 +449,12 @@ instance Binary Usage where |
| 431 | 449 | put_ bh (usg_unit_id usg)
|
| 432 | 450 | put_ bh (usg_iface_hash usg)
|
| 433 | 451 | |
| 452 | + put_ bh usg@UsageDirectory{} = do
|
|
| 453 | + putByte bh 5
|
|
| 454 | + put_ bh (usg_dir_path usg)
|
|
| 455 | + put_ bh (usg_dir_hash usg)
|
|
| 456 | + put_ bh (usg_dir_label usg)
|
|
| 457 | + |
|
| 434 | 458 | get bh = do
|
| 435 | 459 | h <- getByte bh
|
| 436 | 460 | case h of
|
| ... | ... | @@ -462,6 +486,12 @@ instance Binary Usage where |
| 462 | 486 | uid <- get bh
|
| 463 | 487 | hash <- get bh
|
| 464 | 488 | return UsageHomeModuleInterface { usg_mod_name = mod, usg_unit_id = uid, usg_iface_hash = hash }
|
| 489 | + 5 -> do
|
|
| 490 | + dp <- get bh
|
|
| 491 | + hash <- get bh
|
|
| 492 | + label <- get bh
|
|
| 493 | + return UsageDirectory { usg_dir_path = dp, usg_dir_hash = hash, usg_dir_label = label }
|
|
| 494 | + |
|
| 465 | 495 | i -> error ("Binary.get(Usage): " ++ show i)
|
| 466 | 496 | |
| 467 | 497 | -- | Records the imports that we depend on from a home module,
|
| ... | ... | @@ -232,6 +232,11 @@ Cmm |
| 232 | 232 | They are replaced, respectively, by ``SpecialiseEP``, ``pragSpecED`` and
|
| 233 | 233 | ``pragSpecInlED``.
|
| 234 | 234 | |
| 235 | +- We have added the ``addDependentDirectory`` function to match
|
|
| 236 | + ``addDependentFile``, which adds a directory to the list of dependencies that
|
|
| 237 | + the recompilation checker will look at to determine if a module needs to be
|
|
| 238 | + recompiled.
|
|
| 239 | + |
|
| 235 | 240 | Included libraries
|
| 236 | 241 | ~~~~~~~~~~~~~~~~~~
|
| 237 | 242 |
| ... | ... | @@ -779,9 +779,9 @@ the total time spent profiling. |
| 779 | 779 | Cost-centre break-down
|
| 780 | 780 | ^^^^^^^^^^^^^^^^^^^^^^
|
| 781 | 781 | |
| 782 | -A variable-length packet encoding a heap profile sample broken down by,
|
|
| 783 | - * cost-centre (:rts-flag:`-hc`)
|
|
| 784 | - |
|
| 782 | +A variable-length packet encoding a heap profile sample.
|
|
| 783 | +This event is only emitted when the heap profile type is set to :rts-flag:`-hc` or :rts-flag:`-hb`.
|
|
| 784 | +Otherwise, a :event-type:`HEAP_PROF_SAMPLE_STRING` event is emitted instead.
|
|
| 785 | 785 | |
| 786 | 786 | .. event-type:: HEAP_PROF_SAMPLE_COST_CENTRE
|
| 787 | 787 | |
| ... | ... | @@ -796,11 +796,19 @@ A variable-length packet encoding a heap profile sample broken down by, |
| 796 | 796 | String break-down
|
| 797 | 797 | ^^^^^^^^^^^^^^^^^
|
| 798 | 798 | |
| 799 | -A variable-length event encoding a heap sample broken down by,
|
|
| 799 | +A variable-length event encoding a heap sample.
|
|
| 800 | +The content of the sample label varies depending on the heap profile type:
|
|
| 801 | + |
|
| 802 | + * :rts-flag:`-hT` The sample label contains a closure type, e.g., ``"ghc-bignum:GHC.Num.Integer.IS"``.
|
|
| 803 | + * :rts-flag:`-hm` The sample label contains a module name, e.g., ``"GHC.Num.Integer"``.
|
|
| 804 | + * :rts-flag:`-hd` The sample label contains a closure description, e.g., ``"IS"``.
|
|
| 805 | + * :rts-flag:`-hy` The sample label contains a type description, e.g., ``"Integer"``.
|
|
| 806 | + * :rts-flag:`-he` The sample label contains a stringified era, e.g., ``"1"``.
|
|
| 807 | + * :rts-flag:`-hr` The sample label contains a retainer set description, e.g., ``"(184)$stoIntegralSized1"``.
|
|
| 808 | + * :rts-flag:`-hi` The sample label contains a stringified pointer, e.g., ``"0x1008b7588"``,
|
|
| 809 | + which can be matched to an info table description emitted by the :event-type:`IPE` event.
|
|
| 800 | 810 | |
| 801 | - * type description (:rts-flag:`-hy`)
|
|
| 802 | - * closure description (:rts-flag:`-hd`)
|
|
| 803 | - * module (:rts-flag:`-hm`)
|
|
| 811 | +If the heap profile type is set to :rts-flag:`-hc` or :rts-flag:`-hb`, a :event-type:`HEAP_PROF_SAMPLE_COST_CENTRE` event is emitted instead.
|
|
| 804 | 812 | |
| 805 | 813 | .. event-type:: HEAP_PROF_SAMPLE_STRING
|
| 806 | 814 | |
| ... | ... | @@ -808,7 +816,7 @@ A variable-length event encoding a heap sample broken down by, |
| 808 | 816 | :length: variable
|
| 809 | 817 | :field Word8: profile ID
|
| 810 | 818 | :field Word64: heap residency in bytes
|
| 811 | - :field String: type or closure description, or module name
|
|
| 819 | + :field String: sample label
|
|
| 812 | 820 | |
| 813 | 821 | .. _time-profiler-events:
|
| 814 | 822 |
| ... | ... | @@ -710,7 +710,7 @@ beautiful sight! |
| 710 | 710 | You can read about :ghc-wiki:`how all this works <commentary/compiler/recompilation-avoidance>` in the GHC commentary.
|
| 711 | 711 | |
| 712 | 712 | Recompilation for Template Haskell and Plugins
|
| 713 | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
| 713 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 714 | 714 | |
| 715 | 715 | Recompilation checking gets a bit more complicated when using Template Haskell or
|
| 716 | 716 | plugins. Both these features execute code at compile time and so if any of the
|
| ... | ... | @@ -727,6 +727,19 @@ if ``foo`` is from module ``A`` and ``bar`` is from module ``B``, the module wil |
| 727 | 727 | now depend on ``A.o`` and ``B.o``, if either of these change then the module will
|
| 728 | 728 | be recompiled.
|
| 729 | 729 | |
| 730 | +``addDependentFile`` and ``addDependentDirectory``
|
|
| 731 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
| 732 | + |
|
| 733 | +When using Template Haskell or plugins, you can use the functions
|
|
| 734 | +``addDependentFile`` and ``addDependentDirectory`` to add additional
|
|
| 735 | +dependencies to the module being compiled.
|
|
| 736 | + |
|
| 737 | +- When adding a file, this means that the contents of the file changing between
|
|
| 738 | + compilations will trigger a recompilation of the module.
|
|
| 739 | +- When adding a directory, this means that any file or subdirectory *added* to or
|
|
| 740 | + *removed* from the directory will trigger recompilation of the module, so
|
|
| 741 | + it is not a recursive dependency.
|
|
| 742 | + |
|
| 730 | 743 | .. _mutual-recursion:
|
| 731 | 744 | |
| 732 | 745 | Mutually recursive modules and hs-boot files
|
| ... | ... | @@ -1047,7 +1047,7 @@ class Functor f where |
| 1047 | 1047 | -- * sequence computations and combine their results ('<*>' and 'liftA2').
|
| 1048 | 1048 | --
|
| 1049 | 1049 | -- A minimal complete definition must include implementations of 'pure'
|
| 1050 | +-- and one of either '<*>' or 'liftA2'. If it defines both, then they must behave
|
|
| 1050 | 1051 | -- the same as their default definitions:
|
| 1051 | 1052 | --
|
| 1052 | 1053 | -- @('<*>') = 'liftA2' 'id'@
|
| ... | ... | @@ -135,6 +135,9 @@ class (MonadIO m, MonadFail m) => Quasi m where |
| 135 | 135 | -- | See 'addDependentFile'.
|
| 136 | 136 | qAddDependentFile :: FilePath -> m ()
|
| 137 | 137 | |
| 138 | + -- | See 'addDependentDirectory'.
|
|
| 139 | + qAddDependentDirectory :: FilePath -> m ()
|
|
| 140 | + |
|
| 138 | 141 | -- | See 'addTempFile'.
|
| 139 | 142 | qAddTempFile :: String -> m FilePath
|
| 140 | 143 | |
| ... | ... | @@ -181,30 +184,31 @@ instance Quasi IO where |
| 181 | 184 | qReport True msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
|
| 182 | 185 | qReport False msg = hPutStrLn stderr ("Template Haskell error: " ++ msg)
|
| 183 | 186 | |
| 184 | - qLookupName _ _ = badIO "lookupName"
|
|
| 185 | - qReify _ = badIO "reify"
|
|
| 186 | - qReifyFixity _ = badIO "reifyFixity"
|
|
| 187 | - qReifyType _ = badIO "reifyFixity"
|
|
| 188 | - qReifyInstances _ _ = badIO "reifyInstances"
|
|
| 189 | - qReifyRoles _ = badIO "reifyRoles"
|
|
| 190 | - qReifyAnnotations _ = badIO "reifyAnnotations"
|
|
| 191 | - qReifyModule _ = badIO "reifyModule"
|
|
| 192 | - qReifyConStrictness _ = badIO "reifyConStrictness"
|
|
| 193 | - qLocation = badIO "currentLocation"
|
|
| 194 | - qRecover _ _ = badIO "recover" -- Maybe we could fix this?
|
|
| 195 | - qGetPackageRoot = badIO "getProjectRoot"
|
|
| 196 | - qAddDependentFile _ = badIO "addDependentFile"
|
|
| 197 | - qAddTempFile _ = badIO "addTempFile"
|
|
| 198 | - qAddTopDecls _ = badIO "addTopDecls"
|
|
| 199 | - qAddForeignFilePath _ _ = badIO "addForeignFilePath"
|
|
| 200 | - qAddModFinalizer _ = badIO "addModFinalizer"
|
|
| 201 | - qAddCorePlugin _ = badIO "addCorePlugin"
|
|
| 202 | - qGetQ = badIO "getQ"
|
|
| 203 | - qPutQ _ = badIO "putQ"
|
|
| 204 | - qIsExtEnabled _ = badIO "isExtEnabled"
|
|
| 205 | - qExtsEnabled = badIO "extsEnabled"
|
|
| 206 | - qPutDoc _ _ = badIO "putDoc"
|
|
| 207 | - qGetDoc _ = badIO "getDoc"
|
|
| 187 | + qLookupName _ _ = badIO "lookupName"
|
|
| 188 | + qReify _ = badIO "reify"
|
|
| 189 | + qReifyFixity _ = badIO "reifyFixity"
|
|
| 190 | + qReifyType _ = badIO "reifyFixity"
|
|
| 191 | + qReifyInstances _ _ = badIO "reifyInstances"
|
|
| 192 | + qReifyRoles _ = badIO "reifyRoles"
|
|
| 193 | + qReifyAnnotations _ = badIO "reifyAnnotations"
|
|
| 194 | + qReifyModule _ = badIO "reifyModule"
|
|
| 195 | + qReifyConStrictness _ = badIO "reifyConStrictness"
|
|
| 196 | + qLocation = badIO "currentLocation"
|
|
| 197 | + qRecover _ _ = badIO "recover" -- Maybe we could fix this?
|
|
| 198 | + qGetPackageRoot = badIO "getProjectRoot"
|
|
| 199 | + qAddDependentFile _ = badIO "addDependentFile"
|
|
| 200 | + qAddDependentDirectory _ = badIO "AddDependentDirectory"
|
|
| 201 | + qAddTempFile _ = badIO "addTempFile"
|
|
| 202 | + qAddTopDecls _ = badIO "addTopDecls"
|
|
| 203 | + qAddForeignFilePath _ _ = badIO "addForeignFilePath"
|
|
| 204 | + qAddModFinalizer _ = badIO "addModFinalizer"
|
|
| 205 | + qAddCorePlugin _ = badIO "addCorePlugin"
|
|
| 206 | + qGetQ = badIO "getQ"
|
|
| 207 | + qPutQ _ = badIO "putQ"
|
|
| 208 | + qIsExtEnabled _ = badIO "isExtEnabled"
|
|
| 209 | + qExtsEnabled = badIO "extsEnabled"
|
|
| 210 | + qPutDoc _ _ = badIO "putDoc"
|
|
| 211 | + qGetDoc _ = badIO "getDoc"
|
|
| 208 | 212 | |
| 209 | 213 | instance Quote IO where
|
| 210 | 214 | newName = newNameIO
|
| ... | ... | @@ -822,6 +826,26 @@ getPackageRoot :: Q FilePath |
| 822 | 826 | getPackageRoot = Q qGetPackageRoot
|
| 823 | 827 | |
| 824 | 828 | |
| 829 | +-- | Record external directories that runIO is using (dependent upon).
|
|
| 830 | +-- The compiler can then recognize that it should re-compile the Haskell file
|
|
| 831 | +-- when a directory changes.
|
|
| 832 | +--
|
|
| 833 | +-- Expects an absolute directory path.
|
|
| 834 | +--
|
|
| 835 | +-- Notes:
|
|
| 836 | +--
|
|
| 837 | +-- * ghc -M does not know about these dependencies - it does not execute TH.
|
|
| 838 | +--
|
|
| 839 | +-- * The dependency is shallow, based only on the direct content.
|
|
| 840 | +-- Basically, it only sees a list of names. It does not look at directory
|
|
| 841 | +-- metadata, recurse into subdirectories, or look at file contents. As
|
|
| 842 | +-- long as the list of names remains the same, the directory is considered
|
|
| 843 | +-- unchanged.
|
|
| 844 | +--
|
|
| 845 | +-- * The state of the directory is read at the interface generation time,
|
|
| 846 | +-- not at the time of the function call.
|
|
| 847 | +addDependentDirectory :: FilePath -> Q ()
|
|
| 848 | +addDependentDirectory dp = Q (qAddDependentDirectory dp)
|
|
| 825 | 849 | |
| 826 | 850 | -- | Record external files that runIO is using (dependent upon).
|
| 827 | 851 | -- The compiler can then recognize that it should re-compile the Haskell file
|
| ... | ... | @@ -833,7 +857,11 @@ getPackageRoot = Q qGetPackageRoot |
| 833 | 857 | --
|
| 834 | 858 | -- * ghc -M does not know about these dependencies - it does not execute TH.
|
| 835 | 859 | --
|
| 836 | --- * The dependency is based on file content, not a modification time
|
|
| 860 | +-- * The dependency is based on file content, not a modification time or
|
|
| 861 | +-- any other metadata associated with the file (e.g. permissions).
|
|
| 862 | +--
|
|
| 863 | +-- * The state of the file is read at the interface generation time,
|
|
| 864 | +-- not at the time of the function call.
|
|
| 837 | 865 | addDependentFile :: FilePath -> Q ()
|
| 838 | 866 | addDependentFile fp = Q (qAddDependentFile fp)
|
| 839 | 867 | |
| ... | ... | @@ -961,32 +989,33 @@ instance MonadIO Q where |
| 961 | 989 | liftIO = runIO
|
| 962 | 990 | |
| 963 | 991 | instance Quasi Q where
|
| 964 | - qNewName = newName
|
|
| 965 | - qReport = report
|
|
| 966 | - qRecover = recover
|
|
| 967 | - qReify = reify
|
|
| 968 | - qReifyFixity = reifyFixity
|
|
| 969 | - qReifyType = reifyType
|
|
| 970 | - qReifyInstances = reifyInstances
|
|
| 971 | - qReifyRoles = reifyRoles
|
|
| 972 | - qReifyAnnotations = reifyAnnotations
|
|
| 973 | - qReifyModule = reifyModule
|
|
| 974 | - qReifyConStrictness = reifyConStrictness
|
|
| 975 | - qLookupName = lookupName
|
|
| 976 | - qLocation = location
|
|
| 977 | - qGetPackageRoot = getPackageRoot
|
|
| 978 | - qAddDependentFile = addDependentFile
|
|
| 979 | - qAddTempFile = addTempFile
|
|
| 980 | - qAddTopDecls = addTopDecls
|
|
| 981 | - qAddForeignFilePath = addForeignFilePath
|
|
| 982 | - qAddModFinalizer = addModFinalizer
|
|
| 983 | - qAddCorePlugin = addCorePlugin
|
|
| 984 | - qGetQ = getQ
|
|
| 985 | - qPutQ = putQ
|
|
| 986 | - qIsExtEnabled = isExtEnabled
|
|
| 987 | - qExtsEnabled = extsEnabled
|
|
| 988 | - qPutDoc = putDoc
|
|
| 989 | - qGetDoc = getDoc
|
|
| 992 | + qNewName = newName
|
|
| 993 | + qReport = report
|
|
| 994 | + qRecover = recover
|
|
| 995 | + qReify = reify
|
|
| 996 | + qReifyFixity = reifyFixity
|
|
| 997 | + qReifyType = reifyType
|
|
| 998 | + qReifyInstances = reifyInstances
|
|
| 999 | + qReifyRoles = reifyRoles
|
|
| 1000 | + qReifyAnnotations = reifyAnnotations
|
|
| 1001 | + qReifyModule = reifyModule
|
|
| 1002 | + qReifyConStrictness = reifyConStrictness
|
|
| 1003 | + qLookupName = lookupName
|
|
| 1004 | + qLocation = location
|
|
| 1005 | + qGetPackageRoot = getPackageRoot
|
|
| 1006 | + qAddDependentFile = addDependentFile
|
|
| 1007 | + qAddDependentDirectory = addDependentDirectory
|
|
| 1008 | + qAddTempFile = addTempFile
|
|
| 1009 | + qAddTopDecls = addTopDecls
|
|
| 1010 | + qAddForeignFilePath = addForeignFilePath
|
|
| 1011 | + qAddModFinalizer = addModFinalizer
|
|
| 1012 | + qAddCorePlugin = addCorePlugin
|
|
| 1013 | + qGetQ = getQ
|
|
| 1014 | + qPutQ = putQ
|
|
| 1015 | + qIsExtEnabled = isExtEnabled
|
|
| 1016 | + qExtsEnabled = extsEnabled
|
|
| 1017 | + qPutDoc = putDoc
|
|
| 1018 | + qGetDoc = getDoc
|
|
| 990 | 1019 | |
| 991 | 1020 | |
| 992 | 1021 | ----------------------------------------------------
|
| ... | ... | @@ -291,6 +291,7 @@ data THMessage a where |
| 291 | 291 | |
| 292 | 292 | GetPackageRoot :: THMessage (THResult FilePath)
|
| 293 | 293 | AddDependentFile :: FilePath -> THMessage (THResult ())
|
| 294 | + AddDependentDirectory :: FilePath -> THMessage (THResult ())
|
|
| 294 | 295 | AddTempFile :: String -> THMessage (THResult FilePath)
|
| 295 | 296 | AddModFinalizer :: RemoteRef (TH.Q ()) -> THMessage (THResult ())
|
| 296 | 297 | AddCorePlugin :: String -> THMessage (THResult ())
|
| ... | ... | @@ -343,6 +344,7 @@ getTHMessage = do |
| 343 | 344 | 23 -> THMsg <$> (PutDoc <$> get <*> get)
|
| 344 | 345 | 24 -> THMsg <$> GetDoc <$> get
|
| 345 | 346 | 25 -> THMsg <$> return GetPackageRoot
|
| 347 | + 26 -> THMsg <$> AddDependentDirectory <$> get
|
|
| 346 | 348 | n -> error ("getTHMessage: unknown message " ++ show n)
|
| 347 | 349 | |
| 348 | 350 | putTHMessage :: THMessage a -> Put
|
| ... | ... | @@ -373,7 +375,7 @@ putTHMessage m = case m of |
| 373 | 375 | PutDoc l s -> putWord8 23 >> put l >> put s
|
| 374 | 376 | GetDoc l -> putWord8 24 >> put l
|
| 375 | 377 | GetPackageRoot -> putWord8 25
|
| 376 | - |
|
| 378 | + AddDependentDirectory a -> putWord8 26 >> put a
|
|
| 377 | 379 | |
| 378 | 380 | data EvalOpts = EvalOpts
|
| 379 | 381 | { useSandboxThread :: Bool
|
| ... | ... | @@ -198,6 +198,7 @@ instance TH.Quasi GHCiQ where |
| 198 | 198 | qLocation = fromMaybe noLoc . qsLocation <$> getState
|
| 199 | 199 | qGetPackageRoot = ghcCmd GetPackageRoot
|
| 200 | 200 | qAddDependentFile file = ghcCmd (AddDependentFile file)
|
| 201 | + qAddDependentDirectory dir = ghcCmd (AddDependentDirectory dir)
|
|
| 201 | 202 | qAddTempFile suffix = ghcCmd (AddTempFile suffix)
|
| 202 | 203 | qAddTopDecls decls = ghcCmd (AddTopDecls decls)
|
| 203 | 204 | qAddForeignFilePath lang fp = ghcCmd (AddForeignFilePath lang fp)
|
| ... | ... | @@ -32,6 +32,7 @@ module Language.Haskell.TH.Syntax ( |
| 32 | 32 | ModName (..),
|
| 33 | 33 | addCorePlugin,
|
| 34 | 34 | addDependentFile,
|
| 35 | + addDependentDirectory,
|
|
| 35 | 36 | addForeignFile,
|
| 36 | 37 | addForeignFilePath,
|
| 37 | 38 | addForeignSource,
|
| ... | ... | @@ -1523,6 +1523,7 @@ mk/ghcconfig*_test___spaces_ghc*.exe.mk |
| 1523 | 1523 | /tests/th/T8633
|
| 1524 | 1524 | /tests/th/TH_Depends
|
| 1525 | 1525 | /tests/th/TH_Depends_external.txt
|
| 1526 | +/tests/th/TH_Depends_external/dummy.txt
|
|
| 1526 | 1527 | /tests/th/TH_StringPrimL
|
| 1527 | 1528 | /tests/th/TH_import_loop/ModuleA.hi-boot
|
| 1528 | 1529 | /tests/th/TH_import_loop/ModuleA.o-boot
|
| ... | ... | @@ -1715,6 +1715,7 @@ module Language.Haskell.TH.Syntax where |
| 1715 | 1715 | qRunIO :: forall a. GHC.Internal.Types.IO a -> m a
|
| 1716 | 1716 | qGetPackageRoot :: m GHC.Internal.IO.FilePath
|
| 1717 | 1717 | qAddDependentFile :: GHC.Internal.IO.FilePath -> m ()
|
| 1718 | + qAddDependentDirectory :: GHC.Internal.IO.FilePath -> m ()
|
|
| 1718 | 1719 | qAddTempFile :: GHC.Internal.Base.String -> m GHC.Internal.IO.FilePath
|
| 1719 | 1720 | qAddTopDecls :: [Dec] -> m ()
|
| 1720 | 1721 | qAddForeignFilePath :: ForeignSrcLang -> GHC.Internal.Base.String -> m ()
|
| ... | ... | @@ -1726,7 +1727,7 @@ module Language.Haskell.TH.Syntax where |
| 1726 | 1727 | qExtsEnabled :: m [Extension]
|
| 1727 | 1728 | qPutDoc :: DocLoc -> GHC.Internal.Base.String -> m ()
|
| 1728 | 1729 | qGetDoc :: DocLoc -> m (GHC.Internal.Maybe.Maybe GHC.Internal.Base.String)
|
| 1729 | - {-# MINIMAL qNewName, qReport, qRecover, qLookupName, qReify, qReifyFixity, qReifyType, qReifyInstances, qReifyRoles, qReifyAnnotations, qReifyModule, qReifyConStrictness, qLocation, qGetPackageRoot, qAddDependentFile, qAddTempFile, qAddTopDecls, qAddForeignFilePath, qAddModFinalizer, qAddCorePlugin, qGetQ, qPutQ, qIsExtEnabled, qExtsEnabled, qPutDoc, qGetDoc #-}
|
|
| 1730 | + {-# MINIMAL qNewName, qReport, qRecover, qLookupName, qReify, qReifyFixity, qReifyType, qReifyInstances, qReifyRoles, qReifyAnnotations, qReifyModule, qReifyConStrictness, qLocation, qGetPackageRoot, qAddDependentFile, qAddDependentDirectory, qAddTempFile, qAddTopDecls, qAddForeignFilePath, qAddModFinalizer, qAddCorePlugin, qGetQ, qPutQ, qIsExtEnabled, qExtsEnabled, qPutDoc, qGetDoc #-}
|
|
| 1730 | 1731 | type Quote :: (* -> *) -> Constraint
|
| 1731 | 1732 | class GHC.Internal.Base.Monad m => Quote m where
|
| 1732 | 1733 | newName :: GHC.Internal.Base.String -> m Name
|
| ... | ... | @@ -1779,6 +1780,7 @@ module Language.Haskell.TH.Syntax where |
| 1779 | 1780 | type VarStrictType :: *
|
| 1780 | 1781 | type VarStrictType = VarBangType
|
| 1781 | 1782 | addCorePlugin :: GHC.Internal.Base.String -> Q ()
|
| 1783 | + addDependentDirectory :: GHC.Internal.IO.FilePath -> Q ()
|
|
| 1782 | 1784 | addDependentFile :: GHC.Internal.IO.FilePath -> Q ()
|
| 1783 | 1785 | addForeignFile :: ForeignSrcLang -> GHC.Internal.Base.String -> Q ()
|
| 1784 | 1786 | addForeignFilePath :: ForeignSrcLang -> GHC.Internal.IO.FilePath -> Q ()
|
| ... | ... | @@ -43,6 +43,20 @@ TH_Depends: |
| 43 | 43 | '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends
|
| 44 | 44 | ./TH_Depends
|
| 45 | 45 | |
| 46 | +.PHONY: TH_Depends_Dir
|
|
| 47 | +TH_Depends_Dir:
|
|
| 48 | + rm -rf TH_Depends_external
|
|
| 49 | + $(RM) TH_Depends_Dir TH_Depends_Dir.exe
|
|
| 50 | + $(RM) TH_Depends_Dir.o TH_Depends_Dir.hi
|
|
| 51 | + $(RM) TH_Depends_Dir_External.o TH_Depends_Dir_External.hi
|
|
| 52 | + |
|
| 53 | + mkdir TH_Depends_external
|
|
| 54 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends_Dir
|
|
| 55 | + ./TH_Depends_Dir
|
|
| 56 | + sleep 2
|
|
| 57 | + echo "dummy" > TH_Depends_external/dummy.txt
|
|
| 58 | + '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends_Dir
|
|
| 59 | + ./TH_Depends_Dir
|
|
| 46 | 60 | |
| 47 | 61 | T8333:
|
| 48 | 62 | '$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) $(ghcThWayFlags) T8333.hs < /dev/null
|
| 1 | + |
|
| 2 | +{-# LANGUAGE TemplateHaskell #-}
|
|
| 3 | + |
|
| 4 | +module Main where
|
|
| 5 | + |
|
| 6 | +import TH_Depends_Dir_External (checkDirectoryContent)
|
|
| 7 | + |
|
| 8 | +main :: IO ()
|
|
| 9 | +main = putStrLn $checkDirectoryContent |
|
| \ No newline at end of file |
| 1 | +no files?
|
|
| 2 | +yes files! |
|
| \ No newline at end of file |
| 1 | + |
|
| 2 | +module TH_Depends_Dir_External where
|
|
| 3 | + |
|
| 4 | +import Language.Haskell.TH.Syntax
|
|
| 5 | +import Language.Haskell.TH.Lib
|
|
| 6 | +import System.Directory (listDirectory)
|
|
| 7 | + |
|
| 8 | +checkDirectoryContent :: Q Exp
|
|
| 9 | +checkDirectoryContent = do
|
|
| 10 | + qAddDependentDirectory "TH_Depends_external"
|
|
| 11 | + l <- qRunIO $ listDirectory "TH_Depends_external"
|
|
| 12 | + let s = case l of
|
|
| 13 | + [] -> "no files?"
|
|
| 14 | + _ -> "yes files!"
|
|
| 15 | + stringE s |
|
| \ No newline at end of file |
| ... | ... | @@ -214,6 +214,7 @@ test('T5434', [], multimod_compile, |
| 214 | 214 | ['T5434', '-v0 -Wall ' + config.ghc_th_way_flags])
|
| 215 | 215 | test('T5508', normal, compile, ['-v0 -ddump-splices -dsuppress-uniques'])
|
| 216 | 216 | test('TH_Depends', [only_ways(['normal'])], makefile_test, ['TH_Depends'])
|
| 217 | +test('TH_Depends_Dir', [only_ways(['normal'])], makefile_test, ['TH_Depends_Dir'])
|
|
| 217 | 218 | test('T5597', [], multimod_compile, ['T5597', '-v0 ' + config.ghc_th_way_flags])
|
| 218 | 219 | test('T5665', [], multimod_compile, ['T5665', '-v0 ' + config.ghc_th_way_flags])
|
| 219 | 220 | test('T5700', [], multimod_compile,
|