在GHCi内部的包模块中调试IO

时间:2015-02-17 20:18:19

标签: debugging haskell ghci

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

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

由于违规代码不在我自己的模块中,而是在外部包中的模块内部,因此它作为已编译的代码加载,显然我不能在已编译的模块上使用:break 。 / p>

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

  

有一个主要限制:断点和单步仅在解释模块中可用;编译后的代码对调试器是不可见的[5]。

     

[5]请注意,包只包含已编译的代码,因此调试包需要查找其源并直接加载它。

让我们直接尝试一下:

> :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.

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

> :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.

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

修改

我实际上尝试过这个并且得到了令人困惑的结果:

> :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

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


所以,总结一下这个问题:什么是在外部包中调试IO的好方法?

附加说明:

  1. 我确实需要调试包的源代码;事实上,它已被添加到项目中 cabal sandbox add-source

  2. 使用GHCi的另一种选择是向包源添加跟踪,但这是一个不幸的选择,因为它涉及在每次修改时重新编译包(每当我需要有关执行和修改的更多信息时)痕迹),这需要很长时间。使用GHCi进行交互式调试似乎是一个更好的工具,只要我知道如何使用它。

1 个答案:

答案 0 :(得分:0)

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

然而,这不是灵丹妙药。如果包具有冲突的包 - 全局语言扩展(或其他动态标志)或模块名称冲突,它将无法工作。例如,如果您的顶级广告资源包含default-extensions: NoImplicitPrelude且您的依赖关系不合适,那么他们就不会导入前导广告,几乎肯定不会加载。请参阅this GHC bug