• swig教程-指令文件《一》


    Swig文件说明

    常用字段说明

    不同语言之间转换最主要的就是不同语言之间语法的封装,swig就是用来干这些事情的。而这些字段正是指导swig来完成这些操作的指令

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

    module:指定swig会创建的模块

    %module mymodule
    %{
    // 这里是源代码中需要的
    #include "myheader.h"
    %}
    // 这里是转换之后目标代码中需要的
    // Now list ISO C/C++ declarations
    int foo;
    int bar(int x);
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    %{…%}

    • 所有在%{…%}之间的内容会被一字不差的放置到被swig创建的封装的文件中。这个区域通常用来放置一些swig不会生成的定义或者声明,对应C/C++的封装通常用来引入头文件

    %+指令

    • 大多数的swig指令都是这种以%开头的指令,目的就是为了能和C能够很好的区分开来

    • 默认情况下,swig是不会对include进来的头文件中的#include进行展开的,除非你指定-includeall

    %{
    /* Include in the generated wrapper file */
    typedef unsigned int size_t;
    %}
    /* Tell SWIG about it */
    typedef unsigned int size_t;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Or

    %inline %{
    typedef unsigned int size_t;
    %}
    
    • 1
    • 2
    • 3

    像C语言一样,swig中也能使用swig进行类型重定义

    %include 引入头文件

    使用%include指令来引入swig定义的头文件

    %import引入头文件

    如果只是想引入文件使用文件中的宏定义和类型可以使用import

    %import "foo.i"
    
    • 1

    预定义变量

    为了区分不同语言以及在部分指导文件中能够区别进行,siwg中提前预定义了一些变量

    SWIG Always defined when SWIG is processing a file
    SWIGIMPORTED Defined when SWIG is importing a file with %import
    SWIG_VERSION Hexadecimal (binary-coded decimal) number containing SWIG version,
    such as 0x010311 (corresponding to SWIG-1.3.11).
    SWIGCSHARP Defined when using C#
    SWIGD Defined when using D
    SWIGGO Defined when using Go
    SWIGGUILE Defined when using Guile
    SWIGJAVA Defined when using Java
    SWIGJAVASCRIPT Defined when using Javascript
    SWIG_JAVASCRIPT_JSC Defined when using Javascript with -jsc
    SWIG_JAVASCRIPT_V8 Defined when using Javascript with -v8 or -node
    SWIGLUA Defined when using Lua
    SWIGMZSCHEME Defined when using Mzscheme
    SWIGOCAML Defined when using OCaml
    SWIGOCTAVE Defined when using Octave
    SWIGPERL Defined when using Perl
    SWIGPHP Defined when using PHP (any version)
    SWIGPHP7 Defined when using PHP7
    SWIGPYTHON Defined when using Python
    SWIGR Defined when using R
    SWIGRUBY Defined when using Ruby
    SWIGSCILAB Defined when using Scilab
    SWIGTCL Defined when using Tcl
    SWIGXML Defined when using XML
    
    __LINE__ Current line number
    __FILE__ Current file name
    __STDC__ Defined to indicate ISO C
    __cplusplus Defined when -c++ option used
    
    SWIG_D_VERSION Unsigned integer target version when using D
    SWIGGO_CGO Defined when using Go for cgo
    SWIGGO_GCCGO Defined when using Go for gccgo
    SWIGGO_INTGO_SIZE Size of the Go type int when using Go (32 or 64)
    SWIGPYTHON_PY3 Defined when using Python with -py3
    SWIGPYTHON_BUILTIN Defined when using Python with -builtin
    SWIG_RUBY_AUTORENAME Defined when using Ruby with -autorename
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    增强型的宏定义

    为了更好的实现对源码的封装,swig提供了一种增强型的宏定义指令, %define 和 %enddef

    %define ARRAYHELPER(type, name)
    %inline %{
    type *new_ ## name (int nitems) {
    return (type *) malloc(sizeof(type)*nitems);
    }
    void delete_ ## name(type *t) {
    free(t);
    }
    type name ## _get(type *t, int index) {
    return t[index];
    }
    void name ## _set(type *t, int index, type val) {
    t[index] = val;
    }
    %}
    %enddef
    ARRAYHELPER(int, IntArray)
    ARRAYHELPER(double, DoubleArray)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    指令透传

    正常情况下,在需要封装的函数中,swig会将#define进行处理,如果想让对应的宏定义不进行预处理可以在#前面添加%来实现

    %extend Foo {
    void bar() {
        %#ifdef DEBUG
        printf("I'm in bar\n");
        %#endif
    }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    指针处理(cpointer.i)

    在一些函数中需要传入指针,但是在其他函数中可能没有指针这个概念,因此swig特意为指针提供了封装方式%pointer_functions(int**, intp);的含义就是,提供一个函数封装,这个函数封装可以创建指针执行的内容,这里的含义就是申请一块int大小的内存并返回

    %include "cpointer.i"
    /* Create some functions for working with "int *" */
    %pointer_functions(int, intp);
    /* A function that uses an "int *" */
    void add(int x, int y, int *result);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果想处理复杂的或者自定义的class可以使用%pointer_class(int, intp);来进行处理,相比之下使用pointer_class将申请的内容当成一个对象来管理更加的便捷和方便垃圾回收

    %module example
    %include "cpointer.i"
    /* Wrap a class interface around an "int *" */
    %pointer_class(int, intp);
    /* A function that uses an "int *" */
    void add(int x, int y, int *result);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    类型转换

    当一些类型需要转换是可以使用类型转换指令pointer_cast,第一个参数是当前类型,第二个参数是转换之后的参数,第三个是封装的函数名字

    %include "cpointer.i"
    %pointer_cast(int *, unsigned int *, int_to_uint);
    
    • 1
    • 2

    数组(carrays.i)

    使用前先引入头文件,指令方式%array_functions(type, name)

    %include "carrays.i"
    %array_functions(double, doubleArray);
    void print_array(double x[10]);
    
    • 1
    • 2
    • 3

    同样,这里可以使用array_class来封装自定义类型的数组

    %module example
    %include "carrays.i"
    %array_class(double, doubleArray);
    void print_array(double x[10]);
    
    • 1
    • 2
    • 3
    • 4

    内存管理(cmalloc.i)

    swig提供了内存管理的模块,使用这些指令可以对malloc,calloc,realloc和free进行封装,具体的指令形式如下

    %malloc(type [, name=type])
    %calloc(type [, name=type])
    %realloc(type [, name=type])
    %free(type [, name=type])
    %sizeof(type [, name=type])
    %allocators(type [, name=type])
    // SWIG interface
    %include "cmalloc.i"
    %malloc(int);
    %free(int);
    %malloc(int *, intp);
    %free(int *, intp);
    %allocators(double);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    C类型数据封装(cdata.i)

    引入cdata.i模块后,会在封装代码中提供Cdata*, memmove()等函数的封装用于申请和释放C类型数据。

    如果类型已知可以使用以下方式

    %include "carrays.i"
    %include "cdata.i"
    %array_class(int, intArray);
    
    • 1
    • 2
    • 3

    如果类型是未知类型,就需要借助cdata指令了%cdata(type [, name=type])

    内存释放

    当一个C中的函数申请一块内存,并返回一个char *类型时,swig可能会判断不出对应的内容是否需要释放,新版本的swig已经能够对简单的源码进行自行判断,如果源码中是申请了一块内存但是没有释放,在目标代码中swig会默认封装上释放的函数,比如go中没有char * 类型的数据,在进行封装时swig会创建一个string类型数据,并将原有的char *内容赋值到string对象中,然后根据判断自动释放对象,但是函数复杂时就需要进行人为指定了,这时需要用到指令%newobject来进行指定

    %newobject foo;
    char *foo() {
        char *result = (char *) malloc(sizeof(char));
        return result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    STL的支持

    对于STL的支持是一个循序渐进的过程,目前已经支持的STL如下所示

    在这里插入图片描述

    使用STL时需要注意异常的抛出,通常在使用时需要对可能发生的异常进行适当的封装

    %module example
    %include "std_vector.i"
    %typemap(throws) std::out_of_range {
    // custom exception handler
    }
    %template(VectInt) std::vector<int>;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    更加通用的方法是对所有异常进行封装

    %include "exception.i"
    %exception {
        try {
            $action
        } catch (const std::exception& e) {
            SWIG_exception(SWIG_RuntimeError, e.what());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    SWIG_exception(int code, const char *message)用于在封装的目标函数代码中抛出异常,常见的错误类型如下

    SWIG_MemoryError
    SWIG_IOError
    SWIG_RuntimeError
    SWIG_IndexError
    SWIG_TypeError
    SWIG_DivisionByZero
    SWIG_OverflowError
    SWIG_SyntaxError
    SWIG_ValueError
    SWIG_SystemError
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    参数类型(typemaps.i)

    假如有以下函数,如果不对result进行声明,那么swig只会对按照指针的形式处理result参数,如果你直接传入一个空的result底层会在赋值时直接崩溃

    void add(double a, double b, double *result) {
        *result = a + b;
    }
    
    • 1
    • 2
    • 3

    因此需要使用%apply指令来对参数进行指导,对参数添加上指令%apply double *OUTPUT之后,swig已经知道result是一个需要输出的参数,因此会对result的合法性进行检测,如果是异常值(null)那么直接抛出异常

    %include "typemaps.i"
    %apply double *OUTPUT { double *result };
    %inline %{
    extern void add(double a, double b, double *result);
    extern void Sum(double a, double b, double *result);
    %}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    如果有多个参数需要输出,只需要按照列表的形式向后添加即可

    %include "typemaps.i"
    %apply int *OUTPUT { int *width, int *height };
    // Returns a pair (width, height)
    void getwinsize(int winid, int *width, int *height);
    
    • 1
    • 2
    • 3
    • 4

    如果你嫌每次都要写一长串的指令比较麻烦可以将以上过程简化成如下方式,直接将对应的参数更换成OUTPUT即可

    %include "typemaps.i"
    
    %inline %{
    extern void add(double a, double b, double *OUTPUT);
    %}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    另外需要注意的是,一旦使用%apply进行声明,那么后续所有的double *result参数都会被处理,如果想取消%apply的作用需要进行如下声明:

    %clear double *result; // Remove all typemaps for double *result
    
    • 1

    我们更常用的形式是:

    入参

    int *INPUT
    short *INPUT
    long *INPUT
    unsigned int *INPUT
    unsigned short *INPUT
    unsigned long *INPUT
    double *INPUT
    float *INPUT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    出参

    int *OUTPUT
    short *OUTPUT
    long *OUTPUT
    unsigned int *OUTPUT
    unsigned short *OUTPUT
    unsigned long *OUTPUT
    double *OUTPUT
    float *OUTPUT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    即是入参又是出参

    int *INOUT
    short *INOUT
    long *INOUT
    unsigned int *INOUT
    unsigned short *INOUT
    unsigned long *INOUT
    double *INOUT
    float *INOUT
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    以上书写方式,直接放到参数上,等同使用apply的如下指令形式

    // Make double *result an output value
    %apply double *OUTPUT { double *result };
    // Make Int32 *in an input value
    %apply int *INPUT { int32 *in };
    // Make long *x inout
    %apply long *INOUT {long *x};
    ...
    %clear double *result;
    %clear Int32 *in, long *x;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 相关阅读:
    手写raft(一) 实现leader选举
    音视频技术开发周刊 | 258
    ZKP6.2 Discrete-log-based Polynomial Commitments (KZG10)
    利用GitHub实现域名跳转
    Talk2BEV: Language-enhanced Bird’s-eye View Maps for Autonomous Driving
    2. Layui栅格系统和布局
    大数据与AI:解析智慧城市的幕后英雄
    全国各省市建设工程类专业职称评审要求总结(欢迎补充完善、沟通交流)
    Bootstrap 自定义Tooltips背景色样式等
    Twisted 与 Tornado 中的 WebSocket 连接问题及解决方案
  • 原文地址:https://blog.csdn.net/andrewgithub/article/details/126260601