我最近一直在和伊德里斯搞混,并决定尝试使用其Network.Socket
图书馆。我启动了REPL,导入了模块,并使用socket
命令创建了一个套接字。在尝试执行IO
操作时,我遇到以下错误:
failed to construct ffun from (Builtins.MkPair (FFI_C.C_Types (Int)) (Int) (FFI_C.C_IntT (Int) (FFI_C.C_IntNative)) (2),Builtins.MkPair (FFI_C.C_Types (Int)) (Int) (FFI_C.C_IntT (Int) (FFI_C.C_IntNative)) (1),[])
Symbol "socket" not found
user error (Could not call foreign function "socket" with args [2,1,0])
为了查看问题是Network.Socket
特定的,还是仅仅是FFI,我做了一个虚拟函数。
printf : String -> IO ()
printf = foreign FFI_C "printf" (String -> IO ())
执行:x printf "Hello World"
会产生类似的错误:
Symbol "printf" not found
user error (Could not call foreign function "printf" with args ["hello world"])
尽管如此,putStr
工作正常。
我正在运行Idris 9.20,通过cabal安装,-f FFI
设置为编译。我正在使用通过MacPorts安装的libffi 3.4版。
答案 0 :(得分:2)
我认为这与Idris FFI的运作方式有关,这取决于代码是在编译还是解释。在编译代码时,FFI要求在C codegen阶段,命名的C函数在范围内,并且在链接C可执行文件时,链接正确的名称。由于Idris的RTS链接到libc,这使得libc中的许多名称都不需要任何额外的工作(某些名称可能需要%include
来确保包含正确的C头文件以将它们放在范围内)。在解释代码时,解释器在动态加载的库列表中查找FFI调用,这需要不同的指令:文件中的%dynamic
或解释器中的:dynamic
。默认情况下,不会加载任何动态库,因此即使libc中的标准名称也不在范围内。这可以通过在文件中包含%dynamic "libc"
或在REPL命令行中使用:dynamic "libc"
进行一次会话来解决。