Haskell llvm-general JIT:即时调用 C 函数。 Stephen Diehl 的教程
Haskell llvm-general JIT: calling a C function on the fly. Stephen Diehl's tutorial
我在 Linux Mint 盒子上关注 Stephen Diehl's excellent LLVM Haskell tutorial(Linux Mint 17 Qiana,GHC 7.8.4,llvm 3.4)。
我克隆了项目的 github 存储库,并且能够使用包含的 Makefile
.
构建每一章的示例
教程第 4 章介绍了 JIT 编译器:
import qualified LLVM.General.ExecutionEngine as EE
jit :: Context -> (EE.MCJIT -> IO a) -> IO a
jit c = EE.withMCJIT c optlevel model ptrelim fastins
where
optlevel = Just 2 -- optimization level
model = Nothing -- code model ( Default )
ptrelim = Nothing -- frame pointer elimination
fastins = Nothing -- fast instruction selection
runJIT :: AST.Module -> IO (Either String ())
runJIT mod = do
...
jit context $ \executionEngine ->
...
EE.withModuleInEngine executionEngine m $ \ee -> do
mainfn <- EE.getFunction ee (AST.Name "main")
case mainfn of
Just fn -> do
res <- run fn
putStrLn $ "Evaluated to: " ++ show res
Nothing -> return ()
然后教程通过编写C代码来实现操作来扩展语言
/* cbits
$ gcc -fPIC -shared cbits.c -o cbits.so
$ clang -fPIC -shared cbits.c -o cbits.so
*/
#include "stdio.h"
// putchard - putchar that takes a double and returns 0.
double putchard(double X) {
putchar((char)X);
fflush(stdout);
return 0;
}
makefile 通过运行构建项目:
gcc -fPIC -shared src/chapter4/cbits.c -o src/chapter4/cbits.so
ghc -no-user-package-db -package-db .cabal-sandbox/*-packages.conf.d src/chapter4/cbits.so --make src/chapter4/*.hs -o chapter4
但是当我尝试调用 putchard()
时出现错误:
LLVM ERROR: Program used external function 'putchard' which could not be resolved!
我是不是遗漏了什么?
我看到有人对本教程的原始 C++ 版本有类似的问题。他们通常通过向 gcc 构建命令 (-rdynamic
) 添加一个标志来解决它,这应该使链接器将所有符号添加到动态符号 table,而不仅仅是使用的符号。我怀疑 ghc 正在从 executable 文件中剥离 putchard()
。
当我在 OS X 上执行完全相同的步骤时,一切正常,我可以毫无问题地调用 putchard()
。
发生了什么事?
我刚刚在 Centos 7 上尝试 运行 这个项目,它成功了。我的 Mint 机器一定有问题。
也许 GHC 在链接和删除符号时有点过分热心?能否在Main.hs
中使用FFI手动添加引用,然后重新编译。
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
foreign import ccall safe "putchard" putchard
:: CDouble -> CDouble
我在 Linux Mint 盒子上关注 Stephen Diehl's excellent LLVM Haskell tutorial(Linux Mint 17 Qiana,GHC 7.8.4,llvm 3.4)。
我克隆了项目的 github 存储库,并且能够使用包含的 Makefile
.
教程第 4 章介绍了 JIT 编译器:
import qualified LLVM.General.ExecutionEngine as EE
jit :: Context -> (EE.MCJIT -> IO a) -> IO a
jit c = EE.withMCJIT c optlevel model ptrelim fastins
where
optlevel = Just 2 -- optimization level
model = Nothing -- code model ( Default )
ptrelim = Nothing -- frame pointer elimination
fastins = Nothing -- fast instruction selection
runJIT :: AST.Module -> IO (Either String ())
runJIT mod = do
...
jit context $ \executionEngine ->
...
EE.withModuleInEngine executionEngine m $ \ee -> do
mainfn <- EE.getFunction ee (AST.Name "main")
case mainfn of
Just fn -> do
res <- run fn
putStrLn $ "Evaluated to: " ++ show res
Nothing -> return ()
然后教程通过编写C代码来实现操作来扩展语言
/* cbits
$ gcc -fPIC -shared cbits.c -o cbits.so
$ clang -fPIC -shared cbits.c -o cbits.so
*/
#include "stdio.h"
// putchard - putchar that takes a double and returns 0.
double putchard(double X) {
putchar((char)X);
fflush(stdout);
return 0;
}
makefile 通过运行构建项目:
gcc -fPIC -shared src/chapter4/cbits.c -o src/chapter4/cbits.so
ghc -no-user-package-db -package-db .cabal-sandbox/*-packages.conf.d src/chapter4/cbits.so --make src/chapter4/*.hs -o chapter4
但是当我尝试调用 putchard()
时出现错误:
LLVM ERROR: Program used external function 'putchard' which could not be resolved!
我是不是遗漏了什么?
我看到有人对本教程的原始 C++ 版本有类似的问题。他们通常通过向 gcc 构建命令 (-rdynamic
) 添加一个标志来解决它,这应该使链接器将所有符号添加到动态符号 table,而不仅仅是使用的符号。我怀疑 ghc 正在从 executable 文件中剥离 putchard()
。
当我在 OS X 上执行完全相同的步骤时,一切正常,我可以毫无问题地调用 putchard()
。
发生了什么事?
我刚刚在 Centos 7 上尝试 运行 这个项目,它成功了。我的 Mint 机器一定有问题。
也许 GHC 在链接和删除符号时有点过分热心?能否在Main.hs
中使用FFI手动添加引用,然后重新编译。
{-# LANGUAGE ForeignFunctionInterface #-}
import Foreign.C.Types
foreign import ccall safe "putchard" putchard
:: CDouble -> CDouble