我有这个依赖图(忽略对第三方模块的依赖):
Main:
GSI.Util
GSI.Value
GSI.Result
GSI.Eval
GSI.ByteCode
GSI.Thread
GSI.Main:
GSI.Value
GSI.ByteCode
GSI.Thread:
GSI.Util
GSI.RTS
GSI.Value
GSI.Result
GSI.Eval
GSI.Eval:
GSI.Util
GSI.RTS
GSI.Value
GSI.Result
ACE
GSI.Eval (.hs-boot):
GSI.Value
ACE:
GSI.RTS
GSI.Value
GSI.ByteCode
GSI.Result
{-# SOURCE #-} GSI.Eval
GSI.ByteCode:
GSI.Util
GSI.Value
{-# SOURCE #-} GSI.Thread
GSI.ByteCode (.hs-boot):
{-# SOURCE #-} GSI.Value
{-# SOURCE #-} GSI.Thread
GSI.Result:
GSI.Util
GSI.RTS
GSI.Value
GSI.Value:
GSI.Util
GSI.RTS
{-# SOURCE #-} GSI.ByteCode
(我希望进一步削减该图表,但老实说我很遗憾哪些部分是相关的。未列出的.hs-boot文件与我的代码没有依赖关系)。当我做的时候
ghc --make Main.hs
我收到此消息:
[10 of 13] Compiling ACE ( ACE.hs, ACE.o ) [GSI.ByteCode changed]
module GSI.Thread cannot be linked; it is only available as a boot module
究竟是什么?我没有从Main导入GSI.Thread作为启动模块,那么GHC如何声称它只能作为启动模块使用? (而且,就此而言,为什么GHC只能检测到这种情况并自动包含非启动模块?)
答案 0 :(得分:1)
实际问题是ACE和GSI.Value有一个循环依赖:
ACE -> GSI.Value -> GSI.Thread -> GSI.Eval -> ACE
这是一个无法解决的问题,因为ACE在Template Haskell接头中使用GSI.Value中的函数。这要求GHC动态加载GSI.Value以编译ACE;但这显然是不可能的。
解决方案是将Thread类型从GSI.Thread中移出,并转移到一个单独的模块,该模块可以避免对GSI.Eval或GSI.Value的任何依赖。