Haskell llvm-general JIT:动态调用C函数.Stephen Diehl的教程

esa*_*981 6 haskell llvm

我正在关注Stephen Diehl在Linux Mint盒子上的优秀LLVM Haskell教程(Linux Mint 17 Qiana,GHC 7.8.4,llvm 3.4).

我克隆了项目的github repo,我能够通过使用包含来构建每个章节的示例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 ()
Run Code Online (Sandbox Code Playgroud)

然后,本教程通过编写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;
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

但是当我试着打电话时putchard()我得到一个错误:

LLVM ERROR: Program used external function 'putchard' which could not be resolved!
Run Code Online (Sandbox Code Playgroud)

我在这里错过了什么吗?

我见过人们对本教程的原始C++版本有类似的问题.它们通常通过向gcc build命令(-rdynamic)添加一个标志来解决它,该命令应该使链接器将所有符号(不仅仅是已使用的符号表)添加到动态符号表中.我怀疑ghc正在putchard()从可执行文件中删除.

当我在OS XI上执行完全相同的步骤时,一切正常,我可以putchard()毫无问题地打电话.

发生了什么?

我刚尝试在Centos 7上运行该项目并且它有效.我的Mint机器肯定有问题.

Ste*_*ehl 2

也许 GHC 在链接和删除符号时有点过于热心?能否使用FFI中手动添加引用Main.hs,然后重新编译。

{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign.C.Types

foreign import ccall safe "putchard" putchard
    :: CDouble -> CDouble
Run Code Online (Sandbox Code Playgroud)