我正在尝试跟随LLVM bindings教程here,然后遇到段错误。以下代码的工作原理 ,因为它会将模块标题打印到output.ll
,但它也会在某处发生段错误。
module Main where
import Control.Monad.Error
import LLVM.General.Module
import LLVM.General.Context
import qualified LLVM.General.AST as AST
--Create and write out an empty LLVM module
main :: IO ()
main = writeModule (AST.defaultModule { AST.moduleName = "myModule" })
outputFile :: File
outputFile = File "output.ll"
writeModule :: AST.Module -> IO ()
writeModule mod = withContext $ (\context ->
liftError $ withModuleFromAST context mod (\m ->
liftError $ writeLLVMAssemblyToFile outputFile m))
--perform the action, or fail on an error
liftError :: ErrorT String IO a -> IO a
liftError = runErrorT >=> either fail return
我怀疑这与链接教程中的以下提示有关:
记住不要传递或尝试使用括号外的资源非常重要,因为这会导致未定义的行为和/或段错误。
我认为在这种情况下,“括号”是由withContext
函数实现的,这似乎应该处理所有内容。
如果我将writeModule
的定义更改为
writeModule mod = do assembly <- (withContext $ (\context ->
liftError $ withModuleFromAST context mod moduleLLVMAssembly))
putStrLn assembly
也就是说,不是写入文件而是打印出LLVM程序集的字符串表示,而不是抛出段错误。
有没有人有这些绑定的经验?我也有兴趣知道我引用警告的失败案例。也就是说,如何“忘记”不使用括号外的资源?所有似乎需要Context
的函数都需要一个。这种资源范围问题究竟不是Haskell擅长处理的问题吗?
版本信息:
llvm-general-3.4.3.0
LLVM version 3.4
Default target: x86_64-apple-darwin13.2.0
答案 0 :(得分:3)
如果您共享LLVM和cabal环境会有所帮助,LLVM因为与其自身向后兼容而臭名昭着,因此使用最新版本的绑定可能存在问题。
幕后writeLLVMAssemblyToFile
正在使用C ++调用来执行文件IO操作,并推测它在最终确定文件资源时持有对LLVM模块的引用。
尝试使用moduleString
将模块渲染为String,然后仅提升到IO monad以从Haskell调用writeFile
,而不是通过C ++进行写入。
import LLVM.General.Context
import LLVM.General.Module as Mod
import qualified LLVM.General.AST as AST
import Control.Monad.Error
main :: IO ()
main = do
writeModule (AST.defaultModule { AST.moduleName = "myModule" })
return ()
writeModule :: AST.Module -> IO (Either String ())
writeModule ast =
withContext $ \ctx ->
runErrorT $ withModuleFromAST ctx ast $ \m -> do
asm <- moduleString m
liftIO $ writeFile "output.ll" asm
根据我的经验,绑定仍然可能相当脆弱,如果问题仍然存在,您应该在issue tracker上询问。
编辑:这是随后修复的旧版本的解决方法。请参阅:https://github.com/bscarlet/llvm-general/issues/109