我使用GHC API来解析模块。如果模块包含语法错误,GHC API会将它们写入stdout。这会干扰我的程序,这有另一种报告错误的方法。示例会话:
$ prog ../stack/src/Stack/Package.hs
../stack/src/Stack/Package.hs:669:0:
error: missing binary operator before token "("
#if MIN_VERSION_Cabal(1, 22, 0)
^
../stack/src/Stack/Package.hs:783:0:
error: missing binary operator before token "("
#if MIN_VERSION_Cabal(1, 22, 0)
^
../stack/src/Stack/Package.hs
error: 1:1 argon: phase `C pre-processor' failed (exitcode = 1)
只应输出最后一个。如何确保GHC API不输出任何内容?我想避免像silently
这样的库通过将stdout重定向到临时文件来解决问题。
我已经尝试使用GHC.defaultErrorHandler
,但是虽然我可以捕获异常,但GHC API仍会写入stdout。相关代码:
-- | Parse a module with specific instructions for the C pre-processor.
parseModuleWithCpp :: CppOptions
-> FilePath
-> IO (Either (Span, String) LModule)
parseModuleWithCpp cppOptions file =
GHC.defaultErrorHandler GHC.defaultFatalMessager (GHC.FlushOut $ return ()) $
GHC.runGhc (Just libdir) $ do
dflags <- initDynFlags file
let useCpp = GHC.xopt GHC.Opt_Cpp dflags
fileContents <-
if useCpp
then getPreprocessedSrcDirect cppOptions file
else GHC.liftIO $ readFile file
return $
case parseFile dflags file fileContents of
GHC.PFailed ss m -> Left (srcSpanToSpan ss, GHC.showSDoc dflags m)
GHC.POk _ pmod -> Right pmod
此外,通过这种方法,我无法捕获错误消息(我只是得到ExitFailure
)。删除GHC.defaultErrorHandler
行会显示上面显示的输出。
答案 0 :(得分:2)
非常感谢 @adamse 让我指向正确的方向!我在Hint的代码中找到了答案。
覆盖动态标志中的日志记录就足够了:
initDynFlags :: GHC.GhcMonad m => FilePath -> m GHC.DynFlags
initDynFlags file = do
dflags0 <- GHC.getSessionDynFlags
src_opts <- GHC.liftIO $ GHC.getOptionsFromFile dflags0 file
(dflags1, _, _) <- GHC.parseDynamicFilePragma dflags0 src_opts
let dflags2 = dflags1 { GHC.log_action = customLogAction }
void $ GHC.setSessionDynFlags dflags2
return dflags2
customLogAction :: GHC.LogAction
customLogAction dflags severity _ _ msg =
case severity of
GHC.SevFatal -> fail $ GHC.showSDoc dflags msg
_ -> return () -- do nothing in the other cases (debug, info, etc.)
GHC.log_action
的默认实现可在此处找到:
http://haddock.stackage.org/lts-3.10/ghc-7.10.2/src/DynFlags.html#defaultLogAction
解析代码在我的问题中保持不变,删除了不再需要的GHC.defaultErrorHandler
行,假设有人自己捕获异常。
答案 1 :(得分:1)
我之前看过这个问题,然后答案是暂时重定向stdout
和stderr
。
要将stdout
重定向到文件中作为示例:
import GHC.IO.Handle
import System.IO
main = do file <- openFile "stdout" WriteMode
stdout' <- hDuplicate stdout -- you might want to keep track
-- of the original stdout
hDuplicateTo file stdout -- makes the second Handle a
-- duplicate of the first
putStrLn "hi"
hClose file