【发布时间】:2018-04-12 12:01:49
【问题描述】:
我在Main.hs 中有一个模块Main。该程序使用 FFI(特别是 FunPtr)。
当我运行 stack exec ghci 并加载模块 (:l src/Main.hs) 时,它运行良好。
但是,当我将模块编译为可执行文件并运行该可执行文件时,我遇到了崩溃,即分段错误。
因此我想知道是否需要使用某个选项进行编译。处理 FFI 时是否有特定的选项可供使用?我试过-O0,-fllvm,没办法。也许stack exec ghci 包含一个可以与 GHC 一起使用的选项?
另外,是否有一个调试选项可以设置为 GHC 以便使用 gdb 运行可执行文件?我尝试了-g 选项,但gdb 没有找到调试符号。 EDIT这点解决了:gdb在我用stack exec -- ghc -g -rtsopts src/Main.hs编译的时候找到调试符号。
我在 Linux Ubuntu 上使用 GHC 8.2.2。
编辑
这是一个反映我真实程序结构的最小程序。这个工作正常(在 GHCI 中或作为可执行文件),但我仍然包含它。
helloffi.c:
#include <stdlib.h>
double** evalf(double (*f)(double), double x){
double** out = malloc(2 * sizeof(double*));
for(unsigned i=0; i<2; i++){
out[i] = malloc(2 * sizeof(double));
out[i][0] = (*f)(x);
out[i][1] = (*f)(x+1);
}
return out;
}
double sumpointer(double** pptr){
double x=0;
for(unsigned i=0; i<2; i++){
for(unsigned j=0; j<2; j++){
x += pptr[i][j];
}
}
return x;
}
库的主模块,Lib.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module Lib
where
import Foreign.C.Types
import Foreign.Ptr (Ptr, FunPtr, freeHaskellFunPtr)
type CFunction = CDouble -> IO CDouble
foreign import ccall "wrapper" functionPtr
:: CFunction -> IO (FunPtr CFunction)
foreign import ccall "evalf" c_evalf
:: FunPtr CFunction
-> CDouble
-> IO (Ptr (Ptr CDouble))
fun2cfun :: (Double -> Double) -> CFunction
fun2cfun f x =
return $ realToFrac (f (realToFrac x))
evalFun :: (Double -> Double) -> Double -> IO (Ptr (Ptr CDouble))
evalFun f x = do
fPtr <- functionPtr (fun2cfun f)
result <- c_evalf fPtr (realToFrac x)
freeHaskellFunPtr fPtr
return result
foreign import ccall "sumpointer" c_sumpointer
:: Ptr (Ptr CDouble) -> IO CDouble
要编译的模块 Main.hs
module Main
where
import Lib
main :: IO ()
main = do
x <- evalFun (\x -> x*x) 2
y <- c_sumpointer x
print y
【问题讨论】:
-
我明白了,这使得查找特定问题变得非常困难。我不确定一般结构会有所帮助。
-
尝试使用 FFI 制作“Hello World”类型的程序,看看它是否有效。如果问题在于编译过程而不是代码,我们不需要 1000 行程序。
-
很明显,问题不在于您如何编译程序,而在于您如何使用 FFI(或者可能在您的 C 或 Haskell 代码中完全不同)。不看代码是不可能回答这个问题的。您可能想尝试
printf/trace调试、GDB 等。 -
看起来好像您在 C 端导致 未定义的行为,例如通过使用一些指针来访问未分配(或释放)的内存。在 C 领域,UB 并不意味着“肯定会崩溃”。程序可能会崩溃,也可能不会崩溃,具体取决于分配了多少内存,或者分配在哪里等。在 GHCi 下,分配可能是以程序偶然工作的方式完成的,而在 GHC 下,不会发生。这是一个常见的“C 指针地狱”问题,因为通常很难理解哪里出了问题:-(
-
@Euge 我已经解决了一半的问题。
C/marchingcubes.c中的代码无法正确读取C/tables.c中定义的数组的条目。所以我把这些数组移到了C/marchingcubes.c,这样更好,但还有一个问题。
标签: haskell ghc ffi ghci haskell-stack