2.3 一个示例

演示SWIG的最好方法是提供一个简单的例子。考虑如下代码:

  1. /* File : example.c */
  2. double My_variable = 3.0;
  3. /* Compute factorial of n */
  4. int fact(int n) {
  5. if (n <= 1) return 1;
  6. else return n*fact(n-1);
  7. }
  8. /* Compute n mod m */
  9. int my_mod(int n, int m) {
  10. return(n % m);
  11. }

假设你想从Tcl中访问这些函数和全局变量。你可以想下面这样,从编写一个SWIG接口文件开始(按照惯例,这些文件以.i为后缀)。

2.3.1 SWIG接口文件

  1. /* File : example.i */
  2. %module example
  3. %{
  4. /* Put headers and other declarations here */
  5. extern double My_variable;
  6. extern int fact(int);
  7. extern int my_mod(int n, int m);
  8. %}
  9. extern double My_variable;
  10. extern int fact(int);
  11. extern int my_mod(int n, int m);

接口文件中包含了ANSI C 函数原型和变量声明。%module指令为SWIG生成的模块定义了模块名。 %{ %}块提供插入代码的位置,可以插入C语言头文件或其他C声明到生成的包装代码中。

2.3.2 swig命令

SWIG提供了swig命令行程序。我们可以使用它像下面这样构建一个Tcl模块(Linux系统下):

  1. unix > swig -tcl example.i
  2. unix > gcc -c -fpic example.c example_wrap.c -I/usr/local/include
  3. unix > gcc -shared example.o example_wrap.o -o example.so
  4. unix > tclsh
  5. % load ./example.so
  6. % fact 4
  7. 24
  8. % my_mod 23 7
  9. 2
  10. % expr $My_variable + 4.5
  11. 7.5
  12. %

swig命令产生一个新的文件example_wrap.c,他需要和example.c文件一起编译。绝大多数的操作系统和脚本语言现在都提供动态库支持。在我们的这个例子中,Tcl模块被编译成一个共享库。当加载后,Tcl可以访问SWIG接口文件中声明的函数及全局变量。看看生成的example_wrap.c,会发现里面乱七八糟的。但是不用担心。

2.3.3 构建Perl5模块

现在,让我们让这些功能用于Perl5模块。不作任何更改,请键入以下内容(Solaris系统):

  1. unix > swig -perl5 example.i
  2. unix > gcc -c example.c example_wrap.c \
  3. -I/usr/local/lib/perl5/sun4-solaris/5.003/CORE
  4. unix > ld -G example.o example_wrap.o -o example.so # This is for Solaris
  5. unix > perl5.003
  6. use example;
  7. print example::fact(4), "\n";
  8. print example::my_mod(23,7), "\n";
  9. print $example::My_variable + 4.5, "\n";
  10. <ctrl-d>
  11. 24
  12. 2
  13. 7.5
  14. unix >

2.3.4 构建Python模块

最后,让我们构建一个Python模块(Irix系统):

  1. unix > swig -python example.i
  2. unix > gcc -c -fpic example.c example_wrap.c -I/usr/local/include/python2.0
  3. unix > gcc -shared example.o example_wrap.o -o _example.so
  4. unix > python
  5. Python 2.0 (#6, Feb 21 2001, 13:29:45)
  6. [GCC egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)] on linux2
  7. Type "copyright", "credits" or "license" for more information.
  8. >>> import example
  9. >>> example.fact(4)
  10. 24
  11. >>> example.my_mod(23,7)
  12. 2
  13. >>> example.cvar.My_variable + 4.5
  14. 7.5

2.3.5 快捷方法

对那些比较懒的程序员,他们想知道为什么我们需要提供额外的接口文件呢。结果可以证明,一般你可以不需要提供它。例如,为构建一个Perl5模块,你可以直接使用C头文件,像下面这样提供一个模块名字:

  1. unix > swig -perl5 -module example example.h
  2. unix > gcc -c example.c example_wrap.c \
  3. -I/usr/local/lib/perl5/sun4-solaris/5.003/CORE
  4. unix > ld -G example.o example_wrap.o -o example.so
  5. unix > perl5.003
  6. use example;
  7. print example::fact(4), "\n";
  8. print example::my_mod(23,7), "\n";
  9. print $example::My_variable + 4.5, "\n";
  10. <ctrl-d>
  11. 24
  12. 2
  13. 7.5