Widnows下创建DLL,及Python中的调用

(节选自: 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

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

新版本的命令选项改了

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多分钟.