<div dir="ltr">Hi all,<div><br></div><div>I'm working on a little program that uses GHC as a library to do some static analysis on a project I'm working on. It runs things as far as the typechecker (so there's no Template Haskell remaining) and then does the analysis on the resulting AST.</div><div><br></div><div>Here is how I'm calling GHC at the moment:</div><div><br></div><div><div><font face="monospace, monospace">runAnalyser :: FilePath -> [String] -> [String] -> IO [(Module, [Fact], [Assertion])]</font></div><div><font face="monospace, monospace">runAnalyser srcDir args modules = do</font></div><div><font face="monospace, monospace">  defaultErrorHandler defaultFatalMessager defaultFlushOut $ do</font></div><div><font face="monospace, monospace">      runGhc (Just libdir) $ do</font></div><div><font face="monospace, monospace">        dflags <- getSessionDynFlags</font></div><div><font face="monospace, monospace">        (dflags', leftover, warnings) <- parseDynamicFlagsCmdLine dflags</font></div><div><font face="monospace, monospace">                                          (map noLoc $ args ++ modules)</font></div><div><font face="monospace, monospace">        setSessionDynFlags dflags'</font></div><div><font face="monospace, monospace">        setTargets =<< forM modules (\exampleModule -></font></div><div><font face="monospace, monospace">          guessTarget (exampleModuleFile srcDir exampleModule) Nothing)</font></div><div><font face="monospace, monospace">        load LoadAllTargets</font></div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">        execWriterT $ forM_ modules $ \exampleModule -> do</font></div><div><font face="monospace, monospace">          modSum <- lift $ getModSummary $ mkModuleName exampleModule</font></div><div><font face="monospace, monospace">          p <- lift $ parseModule modSum</font></div><div><font face="monospace, monospace">          t <- lift $ typecheckModule p</font></div><div><font face="monospace, monospace">          case tm_renamed_source t of</font></div><div><font face="monospace, monospace">            Nothing -> return ()</font></div><div><font face="monospace, monospace">            Just (hsGroup, _, _, _) -> do</font></div><div><font face="monospace, monospace">              assertions <- liftIO $ loadAssertions</font></div><div><font face="monospace, monospace">                          $ exampleModuleFile srcDir exampleModule</font></div><div><font face="monospace, monospace">              let mod = ms_mod $ pm_mod_summary $ tm_parsed_module t</font></div><div><font face="monospace, monospace">              tell [( mod</font></div><div><font face="monospace, monospace">                    , runFactM (moduleName mod) (facts hsGroup)</font></div><div><font face="monospace, monospace">                    , assertions)]</font></div></div><div><br></div><div><br></div><div>The problem I'm currently facing is that this requires me to pass in the arguments to GHC, including where all the package databases are and all the package ids that stack has decided to use. So far, I've just copy-pasted this from the stack log and hard-coded it, but that's clearly not a good long-term solution.</div><div><br></div><div>I've half-heartedly tried to fool stack into running my analyser as the compiler, but stack calls ghc more times than just the one call that I need the arguments from. I could make it pass through to the real ghc but this feels like piling hacks on top of hacks.</div><div><br></div><div>I've also briefly contemplated using the Cabal library to read my .cabal file and work out what to do, but I'm unsure that this would work nicely under stack. At least, I'm not sure quite what to do with all the package databases and other stuff that stack does for you.</div><div><br></div><div>Is there a sensible and robust way to get these args as stack would make them?</div><div><br></div><div>Many thanks,</div><div><br></div><div>David</div><div><br></div><div><br></div><div><br></div></div>