(节选自: http://wiki.python.org/moin/PythonVsHaskell )
需要: GHC, cygwin (dlltool)
目标是创建一个 fact.dll ,将haskell的 fact 函数封装在其中,供其他语言调用
1. 准备 haskell 文件,创建 fact.hs
module Fact where fact :: Int -> IO Int fact n = return (fact' n) fact' n = if n == 1 then 1 else n * fact'(n-1) adder :: Int -> Int -> IO Int adder x y = return (x+y) foreign export stdcall adder :: Int -> Int -> IO Int foreign export stdcall fact :: Int -> IO Int
2. 准备一个 dllMain.c ,作为 dll 的进入点
#include windows.h // 注意尖括号省略了,防止 html 显示问题
#include Rts.h
extern void __stginit_Fact(void);
static char* args[] = { "ghcDll", NULL };
/* N.B. argv arrays must end with NULL */
BOOL
STDCALL
DllMain
( HANDLE hModule
, DWORD reason
, void* reserved
)
{
if (reason == DLL_PROCESS_ATTACH) {
/* By now, the RTS DLL should have been hoisted in, but we need to start it up. */
startupHaskell(1, args, __stginit_Fact);
return TRUE;
}
return TRUE;
}
3. 准备dll DEF 文件,此文件可以通过 dlltool 命令生成。内容如下:
EXPORTS adder = adder@8 @ 1 adder@8 @ 2 fact = fact@4 @ 3 fact@4 @ 4
4. 编译
ghc -c fact.hs -fglasgow-exts ghc -c dllMain.c dlltool -A -z fact.def fact_stub.o --export-all-symbols ghc --mk-dll -o fact.dll fact.o fact_stub.o dllMain.o -optdll-def -optdll fact.def
没有以外的话, fact.dll 就生成了。
在 Python 中通过 ctypes 调用:
from ctypes import *
lib = windll.fact
api = {
# func name restype argtypes
'adder' : (c_int, [c_int, c_int]),
'fact' : (c_int, [c_int]),
}
for func in api:
f = getattr(lib, func)
f.restype, f.argtypes = api[func]
globals()[func] = f
print adder(1,2)
print fact(5)
在其他语言中调用,不需要罗嗦了,不过还是备忘一下: VB 中:
Public Class Form1
Declare Function fact Lib "fact.dll" (ByVal n As Integer) As Integer
Declare Function adder Lib "fact.dll" (ByVal a As Integer, ByVal b As Integer) As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TextBox1.Text = fact(5)
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
TextBox1.Text = adder(3, 5)
End Sub
End Class
Comments
新版本的命令选项改了
ghc ––shared -o .... MyDef.def
见官方文档
http://www.haskell.org/ghc/docs/6.8.1/html/users_guide/win32-dlls.html
不过我遇到一个见鬼的bug
必须
ghc –shared -o .... MyDef.def
(少打一个 "-")
才能编译通过.
浪费我30多分钟.