使用SWIG實現C++擴展Python

 

                                      

1. 直接C擴展Python的方法
     Python的擴展API是主要爲C語言提供的,可以利用該API爲要導出的C函數建立包裝器
(wrapper)。包裝器用來處理Python對象與底層C函數中的變量與所需值之間的轉換,並將C函數註冊到Python的自定義module中。
     假設將要導出的函數成爲模塊函數,對應wrapper中的函數爲包裝函數。則wrapper文
件主要包含以下幾個部分:
Ø        include "Python.h";
Ø        每個模塊函數的包裝函數,即:PyObject* Module_func();
Ø        每個模塊函數的函數定義,即:PyMethodDef ModuleMethods[]對應表;
Ø        模塊的初始化函數:void initModule()部分。
     簡單示例程序:
     假設有以下C文件example.c:
--------------------------------------------------------------------------------
  /**************** example.c ******************/
double My_variable = 3.0;
int fact(int n)
{
        if (n <= 1)    
               return 1;
        else
               return n*fact(n-1);
}

int my_mod(int n, int m)
{
        return (n % m);
}


--------------------------------------------------------------------------------
 


     我們要導出其中的兩個函數fact()和my_mod(),則要爲之寫wrapper。文件內容如下:
--------------------------------------------------------------------------------
/************* example_wrap.c ***************/
#include

extern int fact(int);
extern int my_mod(int, int);

PyObject *fact_wrap(PyObject *self, PyObject *args)
{
        int num;
        if (!PyArg_ParseTuple(args, "i", &num))
                return NULL;
        return Py_BuildValue("i", fact(num));
}

PyObject *my_mod_wrap(PyObject *self, PyObject *args)
{
        int n, m;

        if (!PyArg_ParseTuple(args, "ii", &n, &m))
                return NULL;
        return Py_BuildValue("i", my_mod(n, m));
}

static PyMethodDef example2methods[] = {
{"fact", fact_wrap, METH_VARARGS, "compute fact of a number"},
{"my_mod", my_mod_wrap, METH_VARARGS, "compute the mod of two numbers"},
{NULL, NULL},
};

void initexample2(void)
{
        Py_InitModule("example2", example2methods);
}
--------------------------------------------------------------------------------
 

     編譯連接使用以下命令:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ gcc -fpic -c -I/usr/include/python2.2 -

I/usr/lib/python2.2/config example.c example_wrap2.c
[piaoah@RUDDY example]$ gcc -shared -o example2.so example.o example_wrap2.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------
 

     則生成共享庫文件example2.so。我們可以在Python環境中導入example2模塊,並使用其中的函數:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ python
Python 2.3.2 (#5, Mar 24 2004, 10:17:17)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import example2
>>> example2.fact(5)
120
>>> example2.fact(1)
1
>>> example2.fact(3)
6
>>> example2.fact(6)
720
>>> example2.my_mod(1,3)
1
>>>
--------------------------------------------------------------------------------

  
2. 怎樣用SWIG生成C的wraper
     SWIG是一個自動的擴展構造工具。它讀入註釋的源程序頭文件(後綴爲.i的腳本文件)
,爲python、tcl、perl等多種腳本語言產生wrap代碼。
     步驟大致爲:
(1) 寫源程序;
(2) 寫後綴爲.i的腳本文件;
(3) 使用命令"swig -python example.i"生成example_wrap.c,example_wrap.doc;
(4) 編譯連接成共享庫。


     .i腳本文件的格式很簡單,只需要列出要導出的函數或類型,並註釋必要信息。還以
上面的example.c爲例,寫example.i腳本文件如下:
--------------------------------------------------------------------------------
/**************** example.i ******************/
%module example
%{
#include "example.h"
%}
extern double My_variable;
extern int fact(int);
extern int my_mod(int n, int m);
--------------------------------------------------------------------------------
 
     在命令行輸入以下命令"swig -python example.i",會在當前目錄下生成
example_wrap.c,example_wrap.doc兩個文件。前者即爲example.c的wrap文件,後者爲解釋文件。
     接下來使用編譯連接命令生成example.so文件。命令同第一節:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ gcc -fpic -c -I/usr/include/python2.2
-I/usr/lib/python2.2/config example.c example_wrap2.c
[piaoah@RUDDY example]$ gcc -shared -o example2.so example.o example_wrap2.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------

     接下來就可以在Python環境中使用example模塊中的函數了。


3. 用SWIG生成C++的wraper
     用SWIG生成C++的wrapper過程類似於C wrapper。它的步驟如下:
(1) 寫.cpp源程序;
(2) 寫.i腳本文件;
(3) swig -c++ -python foo.i
生成foo_wrap.c,foo_wrap.doc;
(4) 編譯連接成共享庫foo.so。
則生成Python的foo模塊,可以通過調入foo模塊使用其中的類成員函數、成員變量。
     一個簡單示例:
     假設有如下C++源程序:
--------------------------------------------------------------------------------
/**************** number.h ******************/
class Number
{
public:
        Number(int start);
        ~Number();
        void add(int value);
        void sub(int value);
        void display();
        int data;
};
--------------------------------------------------------------------------------
 

     對應實現的cpp文件如下:
--------------------------------------------------------------------------------
/***************** number.cpp ****************/
#include "number.h"
#include

Number::Number(int start)
{
    data = start;
    printf("Number: %d/n", data);
}

Number::~Number()
{
    printf("~Number: %d/n", data);
}

void Number::add(int value)
{
    data += value;
    printf("add %d/n", value);
}

void Number::sub(int value)
{
    data -= value;
    printf("sub %d/n", value);
}

void Number::display()
{
    printf("Number = %d/n", data);
}
--------------------------------------------------------------------------------
 

     爲之寫number.i文件:
--------------------------------------------------------------------------------
%module Number
%{
#include "number.h"
%}

class Number {
public:
        Number(int start);
        ~Number();
        void add(int value);
        void sub(int value);
        void display();
        int data;
};
--------------------------------------------------------------------------------


     使用命令:"swig -c++ -python number.i",得到number_wrap.c,number_wrap.doc
(有些系統生成的是number.py)兩個文件。
     再使用命令:
--------------------------------------------------------------------------------
[piaoah@RUDDY example]$ g++ -fpic -c -I/usr/include/python2.2 -

I/usr/lib/python2.2/config number.cpp number_wrap.c
[piaoah@RUDDY example]$ g++ -shared -o number.so number.o number_wrap.o
[piaoah@RUDDY example]$
--------------------------------------------------------------------------------

     生成number.so文件,可以在Python環境中使用Number類及其成員函數。但類名和成員函數名稍有變化,具體可見生成的number_wrap.doc(或number.py)文件。
     接下來便可以在python環境中導入number模塊了:
--------------------------------------------------------------------------------
[piaoah@RUDDY NUMBER]$ python
Python 2.3.2 (#5, Mar 24 2004, 10:17:17)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import number
>>> mynum = Number.new_Number(5)
Number: 5
>>> Number.Number_display(mynum)
Number = 5
>>> Number.Number_add(mynum, 1)
add 1
>>> Number.Number_display(mynum)
Number = 6
>>> Number.Number_sub(mynum, 3)
sub 3
>>> Number.Number_display(mynum)
Number = 3
>>> Number.delete_Number(mynum)
~Number: 3
>>>
--------------------------------------------------------------------------------
 

注:這裏使用的SWIG版本爲:swig-1.3.24。

發佈了9 篇原創文章 · 獲贊 2 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章