Hannes Siebenhandl pushed to branch wip/fendor/dep-json at Glasgow Haskell Compiler / GHC

Commits:

20 changed files:

Changes:

  • compiler/GHC/Driver/DynFlags.hs
    ... ... @@ -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    = [],
    

  • compiler/GHC/Driver/MakeFile.hs
    ... ... @@ -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
    
    ... ... @@ -19,8 +21,9 @@ import GHC.Prelude
    19 21
     import GHC qualified
    
    20 22
     
    
    21 23
     import GHC.Data.Bag (listToBag)
    
    24
    +import GHC.Data.FastString (lexicalCompareFS, unpackFS)
    
    22 25
     import GHC.Data.Graph.Directed (SCC (..))
    
    23
    -import GHC.Data.OsPath (unsafeDecodeUtf, unsafeEncodeUtf)
    
    26
    +import GHC.Data.OsPath
    
    24 27
     
    
    25 28
     import GHC.Driver.DynFlags
    
    26 29
     import GHC.Driver.Env
    
    ... ... @@ -52,6 +55,7 @@ import GHC.Unit.State (lookupUnitId)
    52 55
     
    
    53 56
     import GHC.Utils.Error
    
    54 57
     import GHC.Utils.Exception
    
    58
    +import GHC.Utils.Json
    
    55 59
     import GHC.Utils.Logger
    
    56 60
     import GHC.Utils.Misc
    
    57 61
     import GHC.Utils.Outputable
    
    ... ... @@ -63,12 +67,18 @@ import Data.Either
    63 67
     import Data.Foldable (traverse_)
    
    64 68
     import Data.IORef
    
    65 69
     import Data.List (partition)
    
    70
    +import Data.Map.Strict qualified as Map
    
    66 71
     import Data.Maybe (isJust, isNothing)
    
    72
    +import Data.Semigroup qualified as Semigroup
    
    67 73
     import Data.Set qualified as Set
    
    74
    +import GHC.Generics (Generic, Generically (..))
    
    68 75
     import System.Directory
    
    69
    -import System.FilePath
    
    76
    +import qualified System.Directory as Directory
    
    77
    +import System.OsPath as OsPath
    
    70 78
     import System.IO
    
    71 79
     import System.IO.Error (isEOFError)
    
    80
    +import qualified System.OsString as OsString
    
    81
    +import qualified Data.Monoid as Monoid
    
    72 82
     
    
    73 83
     -----------------------------------------------------------------
    
    74 84
     --
    
    ... ... @@ -110,27 +120,53 @@ doMkDependHS srcs = do
    110 120
     
    
    111 121
     doMkDependModuleGraph :: GhcMonad m =>  DynFlags -> ModuleGraph -> m ()
    
    112 122
     doMkDependModuleGraph dflags module_graph = do
    
    123
    +    hsc_env <- getSession
    
    113 124
         logger <- getLogger
    
    114
    -    tmpfs <- hsc_tmpfs <$> getSession
    
    115
    -    let excl_mods = depExcludeMods dflags
    
    125
    +    let
    
    126
    +      tmpfs = hsc_tmpfs hsc_env
    
    127
    +      excl_mods = depExcludeMods dflags
    
    128
    +
    
    129
    +    root_ <- liftIO getCurrentDirectory
    
    130
    +    root <- encodeUtf root_
    
    131
    +    let
    
    132
    +      dep_writer =
    
    133
    +        concat
    
    134
    +        [ [ SomeDependencyWriter $ initFileDepWriter logger root tmpfs dflags
    
    135
    +          ]
    
    136
    +        , [ SomeDependencyWriter $ initJsonDepWriter json_output dflags
    
    137
    +          | Just json_output <- [depJson dflags]
    
    138
    +          ]
    
    139
    +        ]
    
    116 140
     
    
    117
    -    files <- liftIO $ beginMkDependHS logger tmpfs dflags
    
    118
    -    let sorted = GHC.topSortModuleGraph False module_graph Nothing
    
    119 141
     
    
    142
    +    let sorted = GHC.topSortModuleGraph False module_graph Nothing
    
    120 143
         -- Print out the dependencies if wanted
    
    121 144
         liftIO $ debugTraceMsg logger 2 (text "Module dependencies" $$ ppr sorted)
    
    122 145
     
    
    123
    -    -- Process them one by one, dumping results into makefile
    
    124
    -    -- and complaining about cycles
    
    125
    -    hsc_env <- getSession
    
    126
    -    root <- liftIO getCurrentDirectory
    
    127
    -    mapM_ (liftIO . processDeps dflags hsc_env (UniqSet.mkUniqSet excl_mods) root (mkd_tmp_hdl files)) sorted
    
    146
    +    liftIO $ do
    
    128 147
     
    
    129
    -    -- If -ddump-mod-cycles, show cycles in the module graph
    
    130
    -    liftIO $ dumpModCycles logger module_graph
    
    148
    +      writers <- traverse
    
    149
    +        (\ (SomeDependencyWriter writer) -> do
    
    150
    +          backend <- dw_beginWriter writer
    
    151
    +          pure $ SomeActiveDependencyWriter (writer, backend)
    
    152
    +        )
    
    153
    +        dep_writer
    
    154
    +
    
    155
    +      do
    
    156
    +        -- Process them one by one, dumping results and complaining about cycles
    
    157
    +        mapM_ (processDeps dflags hsc_env (UniqSet.mkUniqSet excl_mods) writers) sorted
    
    158
    +
    
    159
    +        -- If -ddump-mod-cycles, show cycles in the module graph
    
    160
    +        liftIO $ dumpModCycles logger module_graph
    
    161
    +
    
    162
    +      -- Tidy up
    
    163
    +      do
    
    164
    +        traverse_
    
    165
    +          (\ (SomeActiveDependencyWriter (writer, backend)) -> do
    
    166
    +            dw_endWriter writer backend
    
    167
    +          )
    
    168
    +          writers
    
    131 169
     
    
    132
    -    -- Tidy up
    
    133
    -    liftIO $ endMkDependHS logger files
    
    134 170
     
    
    135 171
         -- Unconditional exiting is a bad idea.  If an error occurs we'll get an
    
    136 172
         --exception; if that is not caught it's fine, but at least we have a
    
    ... ... @@ -139,67 +175,6 @@ doMkDependModuleGraph dflags module_graph = do
    139 175
     
    
    140 176
         --`GHC.ghcCatch` \_ -> io $ exitWith (ExitFailure 1)
    
    141 177
     
    
    142
    ------------------------------------------------------------------
    
    143
    ---
    
    144
    ---              beginMkDependHs
    
    145
    ---      Create a temporary file,
    
    146
    ---      find the Makefile,
    
    147
    ---      slurp through it, etc
    
    148
    ---
    
    149
    ------------------------------------------------------------------
    
    150
    -
    
    151
    -data MkDepFiles
    
    152
    -  = MkDep { mkd_make_file :: FilePath,          -- Name of the makefile
    
    153
    -            mkd_make_hdl  :: Maybe Handle,      -- Handle for the open makefile
    
    154
    -            mkd_tmp_file  :: FilePath,          -- Name of the temporary file
    
    155
    -            mkd_tmp_hdl   :: Handle }           -- Handle of the open temporary file
    
    156
    -
    
    157
    -beginMkDependHS :: Logger -> TmpFs -> DynFlags -> IO MkDepFiles
    
    158
    -beginMkDependHS logger tmpfs dflags = do
    
    159
    -        -- open a new temp file in which to stuff the dependency info
    
    160
    -        -- as we go along.
    
    161
    -  tmp_file <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "dep"
    
    162
    -  tmp_hdl <- openFile tmp_file WriteMode
    
    163
    -
    
    164
    -        -- open the makefile
    
    165
    -  let makefile = depMakefile dflags
    
    166
    -  exists <- doesFileExist makefile
    
    167
    -  mb_make_hdl <-
    
    168
    -        if not exists
    
    169
    -        then return Nothing
    
    170
    -        else do
    
    171
    -           makefile_hdl <- openFile makefile ReadMode
    
    172
    -
    
    173
    -                -- slurp through until we get the magic start string,
    
    174
    -                -- copying the contents into dep_makefile
    
    175
    -           let slurp = do
    
    176
    -                l <- hGetLine makefile_hdl
    
    177
    -                if (l == depStartMarker)
    
    178
    -                        then return ()
    
    179
    -                        else do hPutStrLn tmp_hdl l; slurp
    
    180
    -
    
    181
    -                -- slurp through until we get the magic end marker,
    
    182
    -                -- throwing away the contents
    
    183
    -           let chuck = do
    
    184
    -                l <- hGetLine makefile_hdl
    
    185
    -                if (l == depEndMarker)
    
    186
    -                        then return ()
    
    187
    -                        else chuck
    
    188
    -
    
    189
    -           catchIO slurp
    
    190
    -                (\e -> if isEOFError e then return () else ioError e)
    
    191
    -           catchIO chuck
    
    192
    -                (\e -> if isEOFError e then return () else ioError e)
    
    193
    -
    
    194
    -           return (Just makefile_hdl)
    
    195
    -
    
    196
    -
    
    197
    -        -- write the magic marker into the tmp file
    
    198
    -  hPutStrLn tmp_hdl depStartMarker
    
    199
    -
    
    200
    -  return (MkDep { mkd_make_file = makefile, mkd_make_hdl = mb_make_hdl,
    
    201
    -                  mkd_tmp_file  = tmp_file, mkd_tmp_hdl  = tmp_hdl})
    
    202
    -
    
    203 178
     --------------------------------------------------------------------------------
    
    204 179
     -- Types abstracting over the output
    
    205 180
     --------------------------------------------------------------------------------
    
    ... ... @@ -207,9 +182,9 @@ beginMkDependHS logger tmpfs dflags = do
    207 182
     data DepNode =
    
    208 183
       DepNode
    
    209 184
         { dn_mod :: Module
    
    210
    -    , dn_src :: FilePath
    
    211
    -    , dn_obj :: FilePath
    
    212
    -    , dn_hi :: FilePath
    
    185
    +    , dn_src :: OsPath
    
    186
    +    , dn_obj :: OsPath
    
    187
    +    , dn_hi :: OsPath
    
    213 188
         , dn_boot :: IsBootInterface
    
    214 189
         , dn_preprocessing :: PreprocessingNode
    
    215 190
         }
    
    ... ... @@ -222,15 +197,24 @@ data PreprocessingNode = PreprocessingNode
    222 197
     data Dep
    
    223 198
       = DepHi
    
    224 199
         { dep_mod :: Module
    
    225
    -    , dep_path :: FilePath
    
    200
    +    , dep_path :: OsPath
    
    226 201
         , dep_unit :: Maybe UnitInfo
    
    227 202
         , dep_local :: Bool
    
    228 203
         , dep_boot :: IsBootInterface
    
    229 204
         }
    
    230 205
       | DepCpp
    
    231
    -    { dep_path :: FilePath
    
    206
    +    { dep_path :: OsPath
    
    232 207
         }
    
    233 208
     
    
    209
    +data SomeDependencyWriter = forall backend . SomeDependencyWriter (DependencyWriter backend)
    
    210
    +
    
    211
    +data SomeActiveDependencyWriter = forall backend . SomeActiveDependencyWriter (DependencyWriter backend, backend)
    
    212
    +
    
    213
    +data DependencyWriter backend = DependencyWriter
    
    214
    +  { dw_beginWriter :: IO backend
    
    215
    +  , dw_writeDependency :: backend -> DepNode -> [Dep] -> IO ()
    
    216
    +  , dw_endWriter :: backend -> IO ()
    
    217
    +  }
    
    234 218
     
    
    235 219
     -----------------------------------------------------------------
    
    236 220
     --
    
    ... ... @@ -241,8 +225,7 @@ data Dep
    241 225
     processDeps :: DynFlags
    
    242 226
                 -> HscEnv
    
    243 227
                 -> UniqSet ModuleName -- ^ Excludes
    
    244
    -            -> FilePath
    
    245
    -            -> Handle           -- Write dependencies to here
    
    228
    +            -> [SomeActiveDependencyWriter]
    
    246 229
                 -> SCC ModuleGraphNode
    
    247 230
                 -> IO ()
    
    248 231
     -- Write suitable dependencies to handle
    
    ... ... @@ -260,23 +243,23 @@ processDeps :: DynFlags
    260 243
     --
    
    261 244
     -- For {-# SOURCE #-} imports the "hi" will be "hi-boot".
    
    262 245
     
    
    263
    -processDeps _ hsc_env _ _ _ (CyclicSCC nodes)
    
    246
    +processDeps _ hsc_env _ _ (CyclicSCC nodes)
    
    264 247
       =     -- There shouldn't be any cycles; report them
    
    265 248
         throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $ cyclicModuleErr nodes
    
    266 249
     
    
    267
    -processDeps _ hsc_env _ _ _ (AcyclicSCC (InstantiationNode _uid node))
    
    250
    +processDeps _ hsc_env _ _ (AcyclicSCC (InstantiationNode _uid node))
    
    268 251
       =     -- There shouldn't be any backpack instantiations; report them as well
    
    269 252
         throwOneError (initSourceErrorContext (hsc_dflags hsc_env)) $
    
    270 253
           mkPlainErrorMsgEnvelope noSrcSpan $
    
    271 254
           GhcDriverMessage $ DriverInstantiationNodeInDependencyGeneration node
    
    272 255
     
    
    273
    -processDeps _dflags _ _ _ _ (AcyclicSCC (LinkNode {})) = return ()
    
    274
    -processDeps _dflags _ _ _ _ (AcyclicSCC (UnitNode {})) = return ()
    
    275
    -processDeps _ _ _ _ _ (AcyclicSCC (ModuleNode _ (ModuleNodeFixed {})))
    
    256
    +processDeps _dflags _ _ _ (AcyclicSCC (LinkNode {})) = return ()
    
    257
    +processDeps _dflags _ _ _ (AcyclicSCC (UnitNode {})) = return ()
    
    258
    +processDeps _ _ _ _ (AcyclicSCC (ModuleNode _ (ModuleNodeFixed {})))
    
    276 259
       -- No dependencies needed for fixed modules (already compiled)
    
    277 260
       = return ()
    
    278 261
     
    
    279
    -processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleNodeCompile node))) = do
    
    262
    +processDeps dflags hsc_env excl_mods backends (AcyclicSCC (ModuleNode _ (ModuleNodeCompile node))) = do
    
    280 263
       pp <- preprocessor
    
    281 264
       let
    
    282 265
         dep_node = mkDepNode pp
    
    ... ... @@ -288,33 +271,33 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleN
    288 271
     
    
    289 272
       if null missing_dep_errs
    
    290 273
         then do
    
    291
    -      writeDependencies include_pkg_deps root hdl extra_suffixes dep_node deps
    
    274
    +      traverse_ (\ (SomeActiveDependencyWriter (writer, backend)) -> dw_writeDependency writer backend dep_node deps) backends
    
    292 275
         else do
    
    293 276
           let sec = initSourceErrorContext (hsc_dflags hsc_env)
    
    294 277
           throwErrors sec (mkMessages (listToBag missing_dep_errs))
    
    295 278
       where
    
    296
    -    extra_suffixes = depSuffixes dflags
    
    297
    -    include_pkg_deps = depIncludePkgDeps dflags
    
    298
    -    src_file = msHsFilePath node
    
    299
    -    mkDepNode opts =
    
    300
    -      DepNode {
    
    301
    -        dn_mod = ms_mod node,
    
    302
    -        dn_src = src_file,
    
    303
    -        dn_obj = msObjFilePath node,
    
    304
    -        dn_hi = msHiFilePath node,
    
    305
    -        dn_boot = isBootSummary node,
    
    306
    -        dn_preprocessing = opts
    
    307
    -      }
    
    279
    +    src_file = msHsFileOsPath node
    
    280
    +    mkDepNode preproc =
    
    281
    +      DepNode
    
    282
    +        { dn_mod = ms_mod node
    
    283
    +        , dn_src = src_file
    
    284
    +        , dn_obj = msObjFileOsPath node
    
    285
    +        , dn_hi = msHiFileOsPath node
    
    286
    +        , dn_boot = isBootSummary node
    
    287
    +        , dn_preprocessing = preproc
    
    288
    +        }
    
    308 289
     
    
    309 290
         preprocessor :: IO PreprocessingNode
    
    310 291
         preprocessor
    
    311
    -      | Just src <- ml_hs_file (ms_location node)
    
    292
    +      | Just src <- ml_hs_file_ospath (ms_location node)
    
    312 293
           = runPipeline (hsc_hooks hsc_env) $ do
    
    313
    -        let (_, suffix) = splitExtension src
    
    314
    -            lit | Unlit _ <- startPhase suffix = True
    
    315
    -                | otherwise = False
    
    316
    -            pipe_env = mkPipeEnv StopPreprocess src Nothing NoOutputFile
    
    317
    -        unlit_fn <- if lit then use (T_Unlit pipe_env hsc_env src) else pure src
    
    294
    +        let
    
    295
    +          (_, suffix) = OsPath.splitExtension src
    
    296
    +          srcFn = unsafeDecodeUtf src
    
    297
    +          lit | Unlit _ <- startPhase (unsafeDecodeUtf suffix) = True
    
    298
    +              | otherwise = False
    
    299
    +          pipe_env = mkPipeEnv StopPreprocess srcFn Nothing NoOutputFile
    
    300
    +        unlit_fn <- if lit then use (T_Unlit pipe_env hsc_env srcFn) else pure srcFn
    
    318 301
             (dflags1, opts, _, _) <- use (T_FileArgs (hsc_logger hsc_env) (hsc_dflags hsc_env) unlit_fn)
    
    319 302
             let pp = pgm_F dflags1
    
    320 303
             pure PreprocessingNode
    
    ... ... @@ -341,10 +324,14 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleN
    341 324
         -- Note that GHC.parseModule may throw an exception if the module
    
    342 325
         -- fails to parse, which may not be desirable (see #16616).
    
    343 326
         find_cpp_deps :: IO [Dep]
    
    344
    -    find_cpp_deps = do
    
    345
    -      session <- Session <$> newIORef hsc_env
    
    346
    -      parsedMod <- reflectGhc (GHC.parseModule node) session
    
    347
    -      pure (DepCpp <$> GHC.pm_extra_src_files parsedMod)
    
    327
    +    find_cpp_deps =
    
    328
    +      if depIncludeCppDeps dflags
    
    329
    +        then do
    
    330
    +          session <- Session <$> newIORef hsc_env
    
    331
    +          parsedMod <- reflectGhc (GHC.parseModule node) session
    
    332
    +          pure (DepCpp . unsafeEncodeUtf <$> GHC.pm_extra_src_files parsedMod)
    
    333
    +        else
    
    334
    +          pure []
    
    348 335
     
    
    349 336
         -- Emit a dependency for each import
    
    350 337
         find_import_deps :: [UnresolvedImport PkgQual] -> IO [Either (MsgEnvelope GhcMessage) Dep]
    
    ... ... @@ -356,7 +343,6 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleN
    356 343
             , not $ mod `UniqSet.elementOfUniqSet` excl_mods
    
    357 344
             ]
    
    358 345
     
    
    359
    -
    
    360 346
     findDependency  :: HscEnv
    
    361 347
                     -> UnresolvedImport PkgQual   -- The import to find
    
    362 348
                     -> IO (Either (MsgEnvelope GhcMessage) Dep)  -- Interface file
    
    ... ... @@ -369,7 +355,7 @@ findDependency hsc_env imp = do
    369 355
           pure $ Right
    
    370 356
             DepHi
    
    371 357
               { dep_mod = dep_mod
    
    372
    -          , dep_path = ml_hi_file loc
    
    358
    +          , dep_path = ml_hi_file_ospath loc
    
    373 359
               , dep_unit = lookupUnitId (hsc_units hsc_env) (moduleUnitId dep_mod)
    
    374 360
               , dep_local = isJust (ml_hs_file loc)
    
    375 361
               , dep_boot = is_boot
    
    ... ... @@ -385,11 +371,83 @@ findDependency hsc_env imp = do
    385 371
         L srcloc mod_name = ui_mod_name imp
    
    386 372
         is_boot           = ui_boot imp
    
    387 373
     
    
    374
    +-----------------------------------------------------------------
    
    375
    +--
    
    376
    +--              beginMkDependHs
    
    377
    +--      Create a temporary file,
    
    378
    +--      find the Makefile,
    
    379
    +--      slurp through it, etc
    
    380
    +--
    
    381
    +-----------------------------------------------------------------
    
    382
    +
    
    383
    +initFileDepWriter :: Logger -> OsPath -> TmpFs -> DynFlags -> DependencyWriter MkDepFiles
    
    384
    +initFileDepWriter logger root tmpfs dflags = DependencyWriter
    
    385
    +  { dw_beginWriter = beginMkDependHS logger tmpfs dflags
    
    386
    +  , dw_writeDependency = \ backend node deps -> do
    
    387
    +      writeDependencies (depIncludePkgDeps dflags) root (mkd_tmp_hdl backend) suffixes node deps
    
    388
    +  , dw_endWriter = endMkDependHS logger
    
    389
    +  }
    
    390
    +  where
    
    391
    +    suffixes = map unsafeEncodeUtf (depSuffixes dflags)
    
    392
    +
    
    393
    +data MkDepFiles
    
    394
    +  = MkDep { mkd_make_file :: FilePath,          -- Name of the makefile
    
    395
    +            mkd_make_hdl  :: Maybe Handle,      -- Handle for the open makefile
    
    396
    +            mkd_tmp_file  :: FilePath,          -- Name of the temporary file
    
    397
    +            mkd_tmp_hdl   :: Handle }           -- Handle of the open temporary file
    
    398
    +
    
    399
    +beginMkDependHS :: Logger -> TmpFs -> DynFlags -> IO MkDepFiles
    
    400
    +beginMkDependHS logger tmpfs dflags = do
    
    401
    +        -- open a new temp file in which to stuff the dependency info
    
    402
    +        -- as we go along.
    
    403
    +  tmp_file <- newTempName logger tmpfs (tmpDir dflags) TFL_CurrentModule "dep"
    
    404
    +  tmp_hdl <- openFile tmp_file WriteMode
    
    405
    +
    
    406
    +        -- open the makefile
    
    407
    +  let makefile = depMakefile dflags
    
    408
    +  exists <- Directory.doesFileExist makefile
    
    409
    +  mb_make_hdl <-
    
    410
    +        if not exists
    
    411
    +        then return Nothing
    
    412
    +        else do
    
    413
    +           makefile_hdl <- openFile makefile ReadMode
    
    414
    +
    
    415
    +                -- slurp through until we get the magic start string,
    
    416
    +                -- copying the contents into dep_makefile
    
    417
    +           let slurp = do
    
    418
    +                l <- hGetLine makefile_hdl
    
    419
    +                if (l == depStartMarker)
    
    420
    +                        then return ()
    
    421
    +                        else do hPutStrLn tmp_hdl l; slurp
    
    422
    +
    
    423
    +                -- slurp through until we get the magic end marker,
    
    424
    +                -- throwing away the contents
    
    425
    +           let chuck = do
    
    426
    +                l <- hGetLine makefile_hdl
    
    427
    +                if (l == depEndMarker)
    
    428
    +                        then return ()
    
    429
    +                        else chuck
    
    430
    +
    
    431
    +           catchIO slurp
    
    432
    +                (\e -> if isEOFError e then return () else ioError e)
    
    433
    +           catchIO chuck
    
    434
    +                (\e -> if isEOFError e then return () else ioError e)
    
    435
    +
    
    436
    +           return (Just makefile_hdl)
    
    437
    +
    
    438
    +
    
    439
    +        -- write the magic marker into the tmp file
    
    440
    +  hPutStrLn tmp_hdl depStartMarker
    
    441
    +
    
    442
    +  return (MkDep { mkd_make_file = makefile, mkd_make_hdl = mb_make_hdl,
    
    443
    +                  mkd_tmp_file  = tmp_file, mkd_tmp_hdl  = tmp_hdl})
    
    444
    +
    
    388 445
     writeDependencies ::
    
    389 446
       Bool ->
    
    390
    -  FilePath ->
    
    447
    +  OsPath ->
    
    391 448
       Handle ->
    
    392
    -  [FilePath] ->
    
    449
    +  [OsString] ->
    
    450
    +  -- ^ Suffixes
    
    393 451
       DepNode ->
    
    394 452
       [Dep] ->
    
    395 453
       IO ()
    
    ... ... @@ -406,7 +464,7 @@ writeDependencies include_pkgs root hdl suffixes node deps =
    406 464
         -- files if the module has a corresponding .hs-boot file (#14482)
    
    407 465
         boot_dep
    
    408 466
           | IsBoot <- dn_boot
    
    409
    -      = [([obj], hi) | (obj, hi) <- zip (suffixed (viaOsPath removeBootSuffix dn_obj)) (suffixed dn_hi)]
    
    467
    +      = [([obj], hi) | (obj, hi) <- zip (suffixed (removeBootSuffix dn_obj)) (suffixed dn_hi)]
    
    410 468
           | otherwise
    
    411 469
           = []
    
    412 470
     
    
    ... ... @@ -414,10 +472,9 @@ writeDependencies include_pkgs root hdl suffixes node deps =
    414 472
         -- e.g.         A.o   : B.hi
    
    415 473
         --              A.x_o : B.x_hi
    
    416 474
         import_dep = \case
    
    417
    -      DepHi {dep_path, dep_boot, dep_unit}
    
    475
    +      DepHi {dep_path, dep_unit}
    
    418 476
             | isNothing dep_unit || include_pkgs
    
    419
    -        , let path = if dep_boot == IsBoot then viaOsPath addBootSuffix dep_path else dep_path
    
    420
    -        -> [([obj], hi) | (obj, hi) <- zip obj_files (suffixed path)]
    
    477
    +        -> [([obj], hi) | (obj, hi) <- zip obj_files (suffixed dep_path)]
    
    421 478
     
    
    422 479
             | otherwise
    
    423 480
             -> []
    
    ... ... @@ -432,10 +489,8 @@ writeDependencies include_pkgs root hdl suffixes node deps =
    432 489
     
    
    433 490
         DepNode {dn_src, dn_obj, dn_hi, dn_boot} = node
    
    434 491
     
    
    435
    -    viaOsPath f a = unsafeDecodeUtf (f (unsafeEncodeUtf a))
    
    436
    -
    
    437 492
     -----------------------------
    
    438
    -writeDependency :: FilePath -> Handle -> [FilePath] -> FilePath -> IO ()
    
    493
    +writeDependency :: OsPath -> Handle -> [OsPath] -> OsPath -> IO ()
    
    439 494
     -- (writeDependency r h [t1,t2] dep) writes to handle h the dependency
    
    440 495
     --      t1 t2 : dep
    
    441 496
     writeDependency root hdl targets dep
    
    ... ... @@ -443,33 +498,30 @@ writeDependency root hdl targets dep
    443 498
                --     c:/foo/...
    
    444 499
                -- on cygwin as make gets confused by the :
    
    445 500
                -- Making relative deps avoids some instances of this.
    
    446
    -           dep' = makeRelative root dep
    
    447
    -           forOutput = escapeSpaces . reslash Forwards . normalise
    
    501
    +           dep' = OsPath.makeRelative root dep
    
    502
    +           forOutput = escapeSpaces . reslash Forwards . unsafeDecodeUtf . OsPath.normalise
    
    448 503
                output = unwords (map forOutput targets) ++ " : " ++ forOutput dep'
    
    449 504
            hPutStrLn hdl output
    
    450 505
     
    
    451 506
     -----------------------------
    
    452 507
     insertSuffixes
    
    453
    -        :: FilePath     -- Original filename;   e.g. "foo.o"
    
    454
    -        -> [String]     -- Suffix prefixes      e.g. ["x_", "y_"]
    
    455
    -        -> [FilePath]   -- Zapped filenames     e.g. ["foo.x_o", "foo.y_o"]
    
    508
    +        :: OsPath     -- Original filename;   e.g. "foo.o"
    
    509
    +        -> [OsString]     -- Suffix prefixes      e.g. ["x_", "y_"]
    
    510
    +        -> [OsPath]   -- Zapped filenames     e.g. ["foo.x_o", "foo.y_o"]
    
    456 511
             -- Note that the extra bit gets inserted *before* the old suffix
    
    457 512
             -- We assume the old suffix contains no dots, so we know where to
    
    458 513
             -- split it
    
    459 514
     insertSuffixes file_name extras
    
    460
    -  = [ basename <.> (extra ++ suffix) | extra <- extras ]
    
    515
    +  = [ basename <.> (extra Monoid.<> suffix) | extra <- extras ]
    
    461 516
       where
    
    462
    -    (basename, suffix) = case splitExtension file_name of
    
    517
    +    (basename, suffix) = case OsPath.splitExtension file_name of
    
    463 518
                              -- Drop the "." from the extension
    
    464
    -                         (b, s) -> (b, drop 1 s)
    
    519
    +                         (b, s) -> (b, OsString.drop 1 s)
    
    465 520
     
    
    466 521
     
    
    467 522
     -----------------------------------------------------------------
    
    468
    ---
    
    469
    ---              endMkDependHs
    
    470
    ---      Complete the makefile, close the tmp file etc
    
    471
    ---
    
    472
    ------------------------------------------------------------------
    
    523
    +-- endMkDependHs
    
    524
    +-- Complete the makefile, close the tmp file etc
    
    473 525
     
    
    474 526
     endMkDependHS :: Logger -> MkDepFiles -> IO ()
    
    475 527
     
    
    ... ... @@ -498,6 +550,185 @@ endMkDependHS logger
    498 550
       showPass logger "Installing new makefile"
    
    499 551
       SysTools.copyFile tmp_file makefile
    
    500 552
     
    
    553
    +-----------------------------------------------------------------
    
    554
    +--
    
    555
    +--              JSON MkDepends output
    
    556
    +--
    
    557
    +-----------------------------------------------------------------
    
    558
    +
    
    559
    +initJsonDepWriter :: FilePath -> DynFlags -> DependencyWriter (JsonOutput DepJson)
    
    560
    +initJsonDepWriter output dflags = DependencyWriter
    
    561
    +  { dw_beginWriter = do
    
    562
    +      mkJsonOutput output initDepJson
    
    563
    +  , dw_writeDependency = \ backend node deps -> do
    
    564
    +      updateJson backend (updateDepJson (depIncludePkgDeps dflags) node deps)
    
    565
    +  , dw_endWriter =
    
    566
    +      writeJsonOutput
    
    567
    +  }
    
    568
    +
    
    569
    +--------------------------------------------------------------------------------
    
    570
    +-- Output interface for json dumps
    
    571
    +
    
    572
    +-- | Resources for a json dump option, used in "GHC.Driver.MakeFile".
    
    573
    +-- The flag @-dep-json@ add an additional output target for dependency
    
    574
    +-- diagnostics.
    
    575
    +data JsonOutput a =
    
    576
    +  JsonOutput {
    
    577
    +    -- | This ref is updated in @processDeps@ incrementally, using a
    
    578
    +    -- flag-specific type.
    
    579
    +    json_ref :: IORef a,
    
    580
    +
    
    581
    +    -- | The output file path specified as argument to the flag.
    
    582
    +    json_path :: FilePath
    
    583
    +  }
    
    584
    +
    
    585
    +-- | TODO: @fendor
    
    586
    +mkJsonOutput ::
    
    587
    +  FilePath ->
    
    588
    +  IO (IORef a) ->
    
    589
    +  IO (JsonOutput a)
    
    590
    +mkJsonOutput json_path mk_ref = do
    
    591
    +  json_ref <- mk_ref
    
    592
    +  pure JsonOutput {json_ref, json_path}
    
    593
    +
    
    594
    +-- | Update the dump data in 'json_ref' if the output target is present.
    
    595
    +updateJson :: JsonOutput a -> (a -> a) -> IO ()
    
    596
    +updateJson JsonOutput {json_ref} f = modifyIORef' json_ref f
    
    597
    +
    
    598
    +-- | Write a json object to the flag-dependent file if the output target is
    
    599
    +-- present.
    
    600
    +writeJsonOutput ::
    
    601
    +  ToJson a =>
    
    602
    +  JsonOutput a ->
    
    603
    +  IO ()
    
    604
    +writeJsonOutput JsonOutput {json_ref, json_path} = do
    
    605
    +  payload <- readIORef json_ref
    
    606
    +  writeJsonFile payload json_path
    
    607
    +
    
    608
    +--------------------------------------------------------------------------------
    
    609
    +-- Output helpers
    
    610
    +
    
    611
    +writeJsonFile :: ToJson a => a -> FilePath -> IO ()
    
    612
    +writeJsonFile doc p = do
    
    613
    +  withAtomicRename p
    
    614
    +    $ \tmp -> writeFile tmp $ showSDocUnsafe $ renderJSON $ json doc
    
    615
    +
    
    616
    +--------------------------------------------------------------------------------
    
    617
    +-- Payload for -dep-json
    
    618
    +
    
    619
    +newtype PackageDeps
    
    620
    +  = PackageDeps (Map.Map (String, UnitId, DPackageId) (Set.Set ModuleName))
    
    621
    +  deriving newtype (Monoid)
    
    622
    +
    
    623
    +newtype DPackageId = DPackageId PackageId
    
    624
    +  deriving newtype (Eq)
    
    625
    +
    
    626
    +instance Ord DPackageId where
    
    627
    +  DPackageId (PackageId d1) `compare` DPackageId (PackageId d2) = d1 `lexicalCompareFS` d2
    
    628
    +
    
    629
    +instance Semigroup PackageDeps where
    
    630
    +  PackageDeps l <> PackageDeps r = PackageDeps (Map.unionWith (Semigroup.<>) l r)
    
    631
    +
    
    632
    +data Deps
    
    633
    +  = Deps
    
    634
    +  { sources :: Set.Set OsPath
    
    635
    +  , modules :: (Set.Set ModuleName, Set.Set ModuleName)
    
    636
    +  , packages :: PackageDeps
    
    637
    +  , cpp :: Set.Set OsPath
    
    638
    +  , options :: [String]
    
    639
    +  , preprocessor :: Maybe FilePath
    
    640
    +  }
    
    641
    +  deriving stock (Generic)
    
    642
    +  deriving (Semigroup, Monoid) via (Generically Deps)
    
    643
    +
    
    644
    +newtype DepJson = DepJson (Map.Map ModuleName Deps)
    
    645
    +
    
    646
    +instance ToJson DepJson where
    
    647
    +  json (DepJson m) =
    
    648
    +    JSObject [
    
    649
    +      (moduleNameString target, JSObject [
    
    650
    +        ("sources", array sources (showOsPath . normalise)),
    
    651
    +        ("modules", array (fst modules) moduleNameString),
    
    652
    +        ("modules-boot", array (snd modules) moduleNameString),
    
    653
    +        ("packages",
    
    654
    +          JSArray
    
    655
    +            [ package name unit_id package_id mods
    
    656
    +            | ((name, unit_id, dpkd_id), mods) <- Map.toList packages
    
    657
    +            , let DPackageId package_id = dpkd_id
    
    658
    +            ]
    
    659
    +        ),
    
    660
    +        ("cpp", array cpp showOsPath),
    
    661
    +        ("options", JSArray $ map JSString options),
    
    662
    +        ("preprocessor", maybe JSNull JSString preprocessor)
    
    663
    +      ])
    
    664
    +      | (target, Deps {packages = PackageDeps packages, ..}) <- Map.toList m
    
    665
    +    ]
    
    666
    +    where
    
    667
    +      package name unit_id (PackageId package_id) mods =
    
    668
    +        JSObject [
    
    669
    +          ("id", JSString (unitIdString unit_id)),
    
    670
    +          ("name", JSString name),
    
    671
    +          ("package-id", JSString (unpackFS package_id)),
    
    672
    +          ("modules", array mods moduleNameString)
    
    673
    +        ]
    
    674
    +
    
    675
    +      array values render = JSArray (fmap (JSString . render) (Set.toList values))
    
    676
    +
    
    677
    +      showOsPath = unsafeDecodeUtf
    
    678
    +
    
    679
    +initDepJson :: IO (IORef DepJson)
    
    680
    +initDepJson = newIORef $ DepJson Map.empty
    
    681
    +
    
    682
    +insertDepJson :: [ModuleName] -> Deps -> DepJson -> DepJson
    
    683
    +insertDepJson targets dep (DepJson m0) =
    
    684
    +  DepJson
    
    685
    +    $ foldl'
    
    686
    +      ( \acc target ->
    
    687
    +          Map.insertWith
    
    688
    +            (Semigroup.<>)
    
    689
    +            target
    
    690
    +            dep
    
    691
    +            acc
    
    692
    +      )
    
    693
    +      m0
    
    694
    +      targets
    
    695
    +
    
    696
    +updateDepJson :: Bool -> DepNode -> [Dep] -> DepJson -> DepJson
    
    697
    +updateDepJson include_pkgs DepNode {..} deps =
    
    698
    +  insertDepJson [moduleName dn_mod] payload
    
    699
    +  where
    
    700
    +    payload = node_data Semigroup.<> foldMap dep deps
    
    701
    +
    
    702
    +    node_data =
    
    703
    +      mempty {
    
    704
    +        sources = Set.singleton dn_src,
    
    705
    +        preprocessor = pn_preprocessor dn_preprocessing,
    
    706
    +        options = pn_options dn_preprocessing
    
    707
    +      }
    
    708
    +
    
    709
    +    dep = \case
    
    710
    +      DepHi {dep_mod, dep_local, dep_unit, dep_boot}
    
    711
    +        | dep_local
    
    712
    +        , let set = Set.singleton $ moduleName dep_mod
    
    713
    +              value | IsBoot <- dep_boot = (Set.empty, set)
    
    714
    +                    | otherwise = (set, Set.empty)
    
    715
    +        -> mempty {modules = value}
    
    716
    +
    
    717
    +        | include_pkgs
    
    718
    +        , Just unit <- dep_unit
    
    719
    +        , let PackageName nameFS = unitPackageName unit
    
    720
    +              name = unpackFS nameFS
    
    721
    +              withLibName (PackageName c) = name ++ ":" ++ unpackFS c
    
    722
    +              lname = maybe name withLibName (unitComponentName unit)
    
    723
    +              key = (lname, unitId unit, DPackageId $ unitPackageId unit)
    
    724
    +        -> mempty {packages = PackageDeps (Map.singleton key (Set.singleton $ moduleName dep_mod))}
    
    725
    +
    
    726
    +        | otherwise
    
    727
    +        -> mempty
    
    728
    +
    
    729
    +      DepCpp {dep_path} ->
    
    730
    +        mempty {cpp = Set.singleton dep_path}
    
    731
    +
    
    501 732
     
    
    502 733
     -----------------------------------------------------------------
    
    503 734
     --              Module cycles
    

  • compiler/GHC/Driver/Session.hs
    ... ... @@ -760,6 +760,12 @@ addOptCmmP f = alterToolSettings $ \s -> s
    760 760
     setDepMakefile :: FilePath -> DynFlags -> DynFlags
    
    761 761
     setDepMakefile f d = d { depMakefile = f }
    
    762 762
     
    
    763
    +setDepJson :: FilePath -> DynFlags -> DynFlags
    
    764
    +setDepJson f d = d { depJson = Just f }
    
    765
    +
    
    766
    +unsetDepJson :: DynFlags -> DynFlags
    
    767
    +unsetDepJson d = d { depJson = Nothing }
    
    768
    +
    
    763 769
     setDepIncludeCppDeps :: Bool -> DynFlags -> DynFlags
    
    764 770
     setDepIncludeCppDeps b d = d { depIncludeCppDeps = b }
    
    765 771
     
    
    ... ... @@ -1245,6 +1251,8 @@ dynamic_flags_deps = [
    1245 1251
             -------- ghc -M -----------------------------------------------------
    
    1246 1252
       , make_ord_flag defGhcFlag "dep-suffix"              (hasArg addDepSuffix)
    
    1247 1253
       , make_ord_flag defGhcFlag "dep-makefile"            (hasArg setDepMakefile)
    
    1254
    +  , make_ord_flag defGhcFlag "dep-json"                (hasArg setDepJson)
    
    1255
    +  , make_ord_flag defGhcFlag "no-dep-json"             (noArg unsetDepJson)
    
    1248 1256
       , make_ord_flag defGhcFlag "include-cpp-deps"
    
    1249 1257
             (noArg (setDepIncludeCppDeps True))
    
    1250 1258
       , make_ord_flag defGhcFlag "include-pkg-deps"
    

  • docs/users_guide/separate_compilation.rst
    ... ... @@ -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``
    

  • testsuite/tests/driver/T24384/A.hs
    1
    +{-# language Strict #-}
    
    2
    +{-# options_ghc -fexpose-all-unfoldings #-}
    
    3
    +module A where
    
    4
    +
    
    5
    +import {-# source #-} C

  • testsuite/tests/driver/T24384/C.hs
    1
    +module C where
    
    2
    +
    
    3
    +import A
    
    4
    +import Data.Set
    
    5
    +
    
    6
    +data C = C

  • testsuite/tests/driver/T24384/C.hs-boot
    1
    +module C where
    
    2
    +
    
    3
    +import E
    
    4
    +
    
    5
    +data C

  • testsuite/tests/driver/T24384/D.hs
    1
    +module D where
    
    2
    +
    
    3
    +import B
    
    4
    +import C

  • testsuite/tests/driver/T24384/E.hs
    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

  • testsuite/tests/driver/T24384/Makefile
    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:
    
    10
    +	$(GHC_PKG_LOCAL) init $(PKGCONF_LOCAL) 2>&1 >/dev/null
    
    11
    +
    
    12
    +	cd dep-internal && \
    
    13
    +		'$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
    
    14
    +			-v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-internal-1-XXX  \
    
    15
    +			-package base \
    
    16
    +			-i. DepInternal
    
    17
    +	$(GHC_PKG_LOCAL) register --force dep-internal/dep-internal.pkg 2>&1 >/dev/null
    
    18
    +
    
    19
    +	cd dep-public && \
    
    20
    +		'$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
    
    21
    +			-v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-public-1-XXX  \
    
    22
    +			-package base \
    
    23
    +			-i. DepPublic
    
    24
    +	$(GHC_PKG_LOCAL) register --force dep-public/dep-public.pkg 2>&1 >/dev/null
    
    25
    +
    
    26
    +	cd dep && \
    
    27
    +		'$(TEST_HC)' $(TEST_HC_OPTS) $(WAY_FLAGS) -hisuf=$(ghciWayExt) $(ghciWayFlags) \
    
    28
    +			-v0 -fno-code -fwrite-interface -hidir outdir -this-unit-id dep-1-XXX \
    
    29
    +			-package-db ../$(PKGCONF_LOCAL) -package-id dep-internal-1-XXX \
    
    30
    +			-i. Dep
    
    31
    +	$(GHC_PKG_LOCAL) register --force dep/dep.pkg 2>&1 >/dev/null
    
    32
    +
    
    33
    +	'$(TEST_HC)' -M -dep-json dep.json -include-pkg-deps -include-cpp-deps \
    
    34
    +		-hide-all-packages -package base -package containers -package template-haskell \
    
    35
    +		-package-db ./$(PKGCONF_LOCAL) -package-id dep-1-XXX -package-id dep-public-1-XXX \
    
    36
    +		A.hs lib/B.hs C.hs D.hs E.hs
    
    37
    +
    
    38
    +	cat dep.json | jq --sort-keys

  • testsuite/tests/driver/T24384/T24384.stdout
    1
    +{
    
    2
    +  "A": {
    
    3
    +    "cpp": [],
    
    4
    +    "modules": [],
    
    5
    +    "modules-boot": [
    
    6
    +      "C"
    
    7
    +    ],
    
    8
    +    "options": [
    
    9
    +      "-XStrict",
    
    10
    +      "-fexpose-all-unfoldings"
    
    11
    +    ],
    
    12
    +    "packages": [
    
    13
    +      {
    
    14
    +        "id": "base-4.23.0.0-inplace",
    
    15
    +        "modules": [
    
    16
    +          "GHC.Essentials",
    
    17
    +          "Prelude"
    
    18
    +        ],
    
    19
    +        "name": "base",
    
    20
    +        "package-id": "base-4.23.0.0"
    
    21
    +      }
    
    22
    +    ],
    
    23
    +    "preprocessor": null,
    
    24
    +    "sources": [
    
    25
    +      "A.hs"
    
    26
    +    ]
    
    27
    +  },
    
    28
    +  "B": {
    
    29
    +    "cpp": [],
    
    30
    +    "modules": [
    
    31
    +      "A"
    
    32
    +    ],
    
    33
    +    "modules-boot": [],
    
    34
    +    "options": [
    
    35
    +      "-F",
    
    36
    +      "-pgmF",
    
    37
    +      "./preproc.sh"
    
    38
    +    ],
    
    39
    +    "packages": [
    
    40
    +      {
    
    41
    +        "id": "base-4.23.0.0-inplace",
    
    42
    +        "modules": [
    
    43
    +          "GHC.Essentials",
    
    44
    +          "Prelude"
    
    45
    +        ],
    
    46
    +        "name": "base",
    
    47
    +        "package-id": "base-4.23.0.0"
    
    48
    +      }
    
    49
    +    ],
    
    50
    +    "preprocessor": "./preproc.sh",
    
    51
    +    "sources": [
    
    52
    +      "lib/B.hs"
    
    53
    +    ]
    
    54
    +  },
    
    55
    +  "C": {
    
    56
    +    "cpp": [],
    
    57
    +    "modules": [
    
    58
    +      "A",
    
    59
    +      "E"
    
    60
    +    ],
    
    61
    +    "modules-boot": [],
    
    62
    +    "options": [],
    
    63
    +    "packages": [
    
    64
    +      {
    
    65
    +        "id": "base-4.23.0.0-inplace",
    
    66
    +        "modules": [
    
    67
    +          "GHC.Essentials",
    
    68
    +          "Prelude"
    
    69
    +        ],
    
    70
    +        "name": "base",
    
    71
    +        "package-id": "base-4.23.0.0"
    
    72
    +      },
    
    73
    +      {
    
    74
    +        "id": "containers-0.8-inplace",
    
    75
    +        "modules": [
    
    76
    +          "Data.Set"
    
    77
    +        ],
    
    78
    +        "name": "containers",
    
    79
    +        "package-id": "containers-0.8"
    
    80
    +      }
    
    81
    +    ],
    
    82
    +    "preprocessor": null,
    
    83
    +    "sources": [
    
    84
    +      "C.hs",
    
    85
    +      "C.hs-boot"
    
    86
    +    ]
    
    87
    +  },
    
    88
    +  "D": {
    
    89
    +    "cpp": [],
    
    90
    +    "modules": [
    
    91
    +      "B",
    
    92
    +      "C"
    
    93
    +    ],
    
    94
    +    "modules-boot": [],
    
    95
    +    "options": [],
    
    96
    +    "packages": [
    
    97
    +      {
    
    98
    +        "id": "base-4.23.0.0-inplace",
    
    99
    +        "modules": [
    
    100
    +          "GHC.Essentials",
    
    101
    +          "Prelude"
    
    102
    +        ],
    
    103
    +        "name": "base",
    
    104
    +        "package-id": "base-4.23.0.0"
    
    105
    +      }
    
    106
    +    ],
    
    107
    +    "preprocessor": null,
    
    108
    +    "sources": [
    
    109
    +      "D.hs"
    
    110
    +    ]
    
    111
    +  },
    
    112
    +  "E": {
    
    113
    +    "cpp": [],
    
    114
    +    "modules": [],
    
    115
    +    "modules-boot": [],
    
    116
    +    "options": [],
    
    117
    +    "packages": [
    
    118
    +      {
    
    119
    +        "id": "base-4.23.0.0-inplace",
    
    120
    +        "modules": [
    
    121
    +          "GHC.Essentials",
    
    122
    +          "Prelude"
    
    123
    +        ],
    
    124
    +        "name": "base",
    
    125
    +        "package-id": "base-4.23.0.0"
    
    126
    +      },
    
    127
    +      {
    
    128
    +        "id": "dep-1-XXX",
    
    129
    +        "modules": [
    
    130
    +          "Dep"
    
    131
    +        ],
    
    132
    +        "name": "dep",
    
    133
    +        "package-id": "dep-1"
    
    134
    +      },
    
    135
    +      {
    
    136
    +        "id": "dep-public-1-XXX",
    
    137
    +        "modules": [
    
    138
    +          "DepPublic"
    
    139
    +        ],
    
    140
    +        "name": "dep-public",
    
    141
    +        "package-id": "dep-public-1"
    
    142
    +      },
    
    143
    +      {
    
    144
    +        "id": "template-haskell-2.25.0.0-inplace",
    
    145
    +        "modules": [
    
    146
    +          "Language.Haskell.TH.Syntax"
    
    147
    +        ],
    
    148
    +        "name": "template-haskell",
    
    149
    +        "package-id": "template-haskell-2.25.0.0"
    
    150
    +      }
    
    151
    +    ],
    
    152
    +    "preprocessor": null,
    
    153
    +    "sources": [
    
    154
    +      "E.hs"
    
    155
    +    ]
    
    156
    +  }
    
    157
    +}

  • testsuite/tests/driver/T24384/all.T
    1
    +test('T24384',
    
    2
    +    [ extra_files(['A.hs', 'lib/', 'C.hs', 'C.hs-boot', 'D.hs', 'E.hs',
    
    3
    +      'dep', 'dep-internal', 'dep-public',
    
    4
    +      'preproc.sh'
    
    5
    +      ])
    
    6
    +    ],
    
    7
    +    makefile_test, [])

  • testsuite/tests/driver/T24384/dep-internal/DepInternal.hs
    1
    +module DepInternal where
    
    2
    +depInt :: ()
    
    3
    +depInt = ()

  • testsuite/tests/driver/T24384/dep-internal/dep-internal.pkg
    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:

  • testsuite/tests/driver/T24384/dep-public/DepPublic.hs
    1
    +module DepPublic where
    
    2
    +depPub :: ()
    
    3
    +depPub = ()

  • testsuite/tests/driver/T24384/dep-public/dep-public.pkg
    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:

  • testsuite/tests/driver/T24384/dep/Dep.hs
    1
    +module Dep where
    
    2
    +import DepInternal
    
    3
    +dep :: ()
    
    4
    +dep = depInt

  • testsuite/tests/driver/T24384/dep/dep.pkg
    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:

  • testsuite/tests/driver/T24384/lib/B.hs
    1
    +{-# options_ghc -F -pgmF ./preproc.sh #-}
    
    2
    +module B where

  • testsuite/tests/driver/T24384/preproc.sh
    1
    +#!/usr/bin/env bash
    
    2
    +
    
    3
    +sed '/preproc/d' $2 > $3
    
    4
    +echo 'import A' >> $3