在GHCi内的封装模块中调试IO [英] Debugging IO in a package module inside GHCi

查看:171
本文介绍了在GHCi内的封装模块中调试IO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Haskell中做低级IO(用于库绑定),并且遇到段错误。我希望使用GHCi的:break 来弄清楚发生了什么,但是会发生什么:

 >导入SDL 
> :break SDL.setPaletteColors
无法在setPaletteColors上设置断点:模块SDL.Video.Renderer未被解释

由于有问题的代码不在我自己的模块中,而是位于外部包中的模块内部,所以它作为编译代码加载,显然我无法在编译模块上使用:break 。 / p>

GHCi手册确认了这一点,并提供了一个提示:


有一个主要限制:断点和单步只有在解释模块;编译后的代码对调试器是不可见的。注意,软件包只包含已编译的代码,因此调试软件包需要找到源代码并直接加载。


我们直接试试它:

 > :加载some_path / sdl2 / src / SDL / Video / Renderer.hs 

some_path / sdl2 / src / SDL / Video / Renderer.hs:101:8:
无法找到模块' Control.Monad.IO.Class'
它是隐藏包'transformers-0.3.0.0'的成员。
也许你需要在你的.cabal文件中添加'变形金刚'到build-depends。
使用-v查看搜索的文件列表。

我可以将依赖关系添加到我的.cabal文件中,但这已经是错误的了。一旦我这样做了:

 > :加载some_path / sdl2 / src / SDL / Video / Renderer.hs 

some_path / sdl2 / src / SDL / Video / Renderer.hs:119:8:
无法找到模块' SDL.Internal.Numbered'
它是程序包'sdl2-2.0.0'中的隐藏模块
使用-v查看搜索的文件列表。

我可以将这些模块公开(可能是通过修改包.cabal?),但在此指出这似乎是一种非常尴尬的做事方式,我没有进一步追求。

编辑:



我实际上已经尝试过,并得到了令人困惑的结果:

 > :加载some_path / sdl2 / src / SDL / Video / Renderer.hs 
[1之1]编译SDL.Video.Renderer(some_path / sdl2 / src / SDL / Video / Renderer.hs,解释)
好的,加载的模块:SDL.Video.Renderer。
> :break SDL.setPaletteColors
不能在SDL.setPaletteColors上设置断点:不解释模块SDL.Video.Renderer

我的(未受教育)猜测:这是因为外部模块仍然作为二进制文件链接到我的代码,并且以解释模式动态加载它并不会改变这一点。




所以,总结一下这个问题:一个外部包装?



其他说明:


  1. 我需要调试的包的来源;事实上,它已经被添加到项目中,使用 cabal sandbox add-source 使用GHCi的另一种选择是添加跟踪包源,但这是一个不幸的选择,因为它涉及每次修改时重新编译包(每当我需要更多关于执行和修改跟踪的信息时),而这需要很长时间。使用GHCi进行交互式调试似乎是更好的工具,只要我知道如何使用它。

  2. 方案

Stack对此有一些支持。运行 stack ghci --load-local-deps $ TARGET 会加载你的项目和包中的任何依赖关系字段 stack.yaml ,包括是否标记为 extra-dep s。那时断点会起作用。您可以通过运行 stack unpack $ PACKAGE 并将它添加到中的 packages 中来调试GHCi中的依赖项。 > stack.yaml



然而,这不是万能的。如果软件包具有冲突的软件包全局语言扩展(或其他动态标志)或模块名称冲突,则不起作用。例如,如果您的顶级包装包含 default-extensions:NoImplicitPrelude ,并且您的依赖关系不包含它们,则它们将不会导入前奏,并且几乎肯定不会加载。请参阅此GHC错误


I'm doing low-level IO (for library bindings) in Haskell and am experiencing a segfault. I would like to use GHCi's :break to figure out what's going on, but here's what happens:

> import SDL
> :break SDL.setPaletteColors
cannot set breakpoint on setPaletteColors: module SDL.Video.Renderer is not interpreted

Since the offending code is not inside my own modules, but rather inside a module in an external package, it's loaded as compiled code and apparently I can't use :break on compiled modules.

GHCi manual confirms this and provides a hint:

There is one major restriction: breakpoints and single-stepping are only available in interpreted modules; compiled code is invisible to the debugger[5].

[5] Note that packages only contain compiled code, so debugging a package requires finding its source and loading that directly.

Let's try it directly:

> :load some_path/sdl2/src/SDL/Video/Renderer.hs

some_path/sdl2/src/SDL/Video/Renderer.hs:101:8:
Could not find module ‘Control.Monad.IO.Class’
It is a member of the hidden package ‘transformers-0.3.0.0’.
Perhaps you need to add ‘transformers’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.

I can add the dependencies to my .cabal file, but this already feels wrong. Once I've done that:

> :load some_path/sdl2/src/SDL/Video/Renderer.hs

some_path/sdl2/src/SDL/Video/Renderer.hs:119:8:
Could not find module ‘SDL.Internal.Numbered’
it is a hidden module in the package ‘sdl2-2.0.0’
Use -v to see a list of the files searched for.

I could make those modules public (probably? by modifying the package .cabal?), but at this point it seems a really awkward way to do things and I didn't pursue it further.

EDIT:

I actually tried that and got the baffling result:

> :load some_path/sdl2/src/SDL/Video/Renderer.hs
[1 of 1] Compiling SDL.Video.Renderer ( some_path/sdl2/src/SDL/Video/Renderer.hs, interpreted )
Ok, modules loaded: SDL.Video.Renderer.
> :break SDL.setPaletteColors
cannot set breakpoint on SDL.setPaletteColors: module SDL.Video.Renderer is not interpreted

My (uneducated) guess: it's because the external module is still linked to my code as a binary, and loading it dynamically in interpreted mode doesn't change that.


So, to sum up the question: what is a good way to debug IO in an external package?

Additional notes:

  1. I do have the source to the package I need to debug; in fact, it's been added to the project with cabal sandbox add-source

  2. An alternative option to using GHCi would be to add traces to the package source, but this is an unfortunate option, since it involves recompilation of the package on each modification (whenever I need more information about the execution and modify the traces), and that takes a really long time. Interactive debugging with GHCi seems a better tool for this job, if only I knew how to use it.

解决方案

Stack has some support for this. Running stack ghci --load-local-deps $TARGET will load your project and any dependencies that are in the packages field of stack.yaml, including if they're marked as extra-deps. Breakpoints will work then. You can debug a dependency in GHCi by running stack unpack $PACKAGE and adding it to packages in stack.yaml.

This is not a panacea however. If the packages have conflicting package-global language extensions (or other dynamic flags) or module name clashes it won't work. For example, if your top-level package has default-extensions: NoImplicitPrelude and your dependencies don't, they won't have a prelude imported and will almost certainly not load. See this GHC bug.

这篇关于在GHCi内的封装模块中调试IO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆