变量属性

使用immutable创建只读字段,使用该字段编辑的变量在对应目标语言中只有对应的GetX接口,无法对值进行修改。

一个变量一旦被标记为immutable之后,只有明确再次指定为mutable,否则一直是只读变量

The %immutable directive enables read-only mode until it is explicitly disabled using the %mutable directive

// File : interface.i
int a; // Can read/write
%immutable;
int b, c, d; // Read only variables
%mutable;
double x, y; // read/write

Compatibility note: Read-only access used to be controlled by a pair of directives %readonly and %readwrite. Although these directives still work, they generate a warning message.

Simply change the directives to %immutable; and %mutable; to silence the warning. Don’t forget the extra semicolon

重命名

有时候将对应语言转换为目标语言时,由于关键字的不同,在该语言中能正常使用的变量在目标语言中可能是关键字,这个时候可以使用rename进行重命名。

// interface.i
// 将源语言中的print函数重命名为my_print这样在目标语言中就可以通过my_print来调用源语言中的print
%rename(my_print) print;
extern void print(const char *);
%rename(foo) a_really_long_and_annoying_name;
extern int a_really_long_and_annoying_name;

rename作用域从开始声明一直到文件结束,所以如果想那个头文件中被重命名需要保证该头文件的引入在rename之后

%rename(my_print) print;
%rename(foo) a_really_long_and_annoying_name;
%include "header.h"
// 双引号添加不添加都无所谓,但是当重命名的名字是C++的关键字是,添加双引号就成为了必须的了
%rename("foo_short") foo(short);
%rename(foo_long) foo(long);
void foo(int);
void foo(short); // Accessed as foo_short()
void foo(long); // Accessed as foo_long()

能够对单个命名通常已经够用了,但swig的功能远不止于此,可以通过匹配进行批量命名,如为所有的函数增加前缀

%rename("myprefix_%s") ""; // print -> myprefix_print

将所有蛇形命名的方式修改为驼峰命名的方式

%rename("%(lowercamelcase)s") ""; // foo_bar -> fooBar; FooBar -> fooBar

剔除一些命名中的字符在使用

%rename("%(strip:[wx])s") ""; // wxHello -> Hello; FooBar -> FooBar

对操作符重载函数进行重命名

%rename(__add__) Complex::operator+;

如果操作符重载是按照友元函数或者全局函数重载的需要按照如下方式进行重命名

%rename(op_j) ::operator+;

同时也支持使用正则进行匹配

// Strip the wx prefix from all identifiers except those starting with wxEVT
%rename("%(regex:/wx(?!EVT)(.*)/\\1/)s") ""; // wxSomeWidget -> SomeWidget
// wxEVT_PAINT -> wxEVT_PAINT
// Apply a rule for renaming the enum elements to avoid the common prefixes
// which are redundant in C#/Java
%rename("%(regex:/^([A-Z][a-z]+)+_(.*)/\\2/)s", %$isenumitem) ""; // Colour_Red -> Red
// Remove all "Set/Get" prefixes.
%rename("%(regex:/^(Set|Get)(.*)/\\2/)s") ""; // SetValue -> Value
// GetValue -> Value

Ignore

使用ignore可以指示swig忽略一些不需要封装的内容

%ignore print; // Ignore all declarations named print
%ignore MYMACRO; // Ignore a macro
...
#define MYMACRO 123
void print(const char *);

可以选择忽略大多数符号,只对其中一小部分进行封装

Using the techniques described above it is possible to ignore everything in a header and then selectively wrap a few chosen methods or classes. For example, consider a header, myheader.h

which has many classes in it and just the one class called Star is wanted within this header, the following approach could be taken:

%ignore ""; // Ignore everything
// Unignore chosen class 'Star'
%rename("%s") Star;
// As the ignore everything will include the constructor, destructor, methods etc
// in the class, these have to be explicitly unignored too:
%rename("%s") Star::Star;
%rename("%s") Star::~Star;
%rename("%s") Star::shine; // named method
%include "myheader.h"

同样可以按照类型进行忽略

%rename($ignore, %$isclass) ""; // Only ignore all classes
%rename("%s") Star; // Unignore 'Star'
%include "myheader.h"

回调函数

一些需要传入回调的函数,需要提前声明,不能将目标函数实现的函数直接传入

/* Function with a callback */
int binary_op(int a, int b, int (*op)(int, int));
/* Some callback functions */
// 要将将要使用的回调函数传入
%constant int add(int, int);
%constant int sub(int, int);
%constant int mul(int, int);

一旦声明为回调函数,将不能在目标函数中被当成普通函数使用,如果一个函数即当成回调函数也想当成普通函数调用,可以按照如下方式进行声明

/* Function with a callback */
int binary_op(int a, int b, int (*op)(int, int));
/* Some callback functions */
%callback("%s_cb");
int add(int, int);
int sub(int, int);
int mul(int, int);
%nocallback;

构造与析枸

Swig 为每个C++的类生成默认的构造函数和析枸函数,如果不需要可以使用参数选项或者指令进行禁止

If you don’t want SWIG to generate default constructors for your interfaces, you can use the %nodefaultctor directive or the -nodefaultctor command line option. For example:

swig -nodefaultctor example.i

Or

%module foo
...
%nodefaultctor; // Don't create default constructors
... declarations ...
%clearnodefaultctor; // Re-enable default constructors

或者你可以更加精确的指定那个类不创建构造函数

%nodefaultctor Foo; // No default constructor for Foo
...
struct Foo { // No default constructor generated.
};
struct Bar { // Default constructor generated.
};

虽然,不创建析枸函数往往会导致内存泄露,但是swig还是允许你控制不创建析枸函数通过nodefaultdtor指定不需要析枸函数的类型

%nodefaultdtor Foo; // No default/implicit destructor for Foo
...
struct Foo { // No default destructor is generated.
};
struct Bar { // Default destructor generated.
};

Note: There are also the-nodefault option and %nodefault directive, which disable both the default or implicit destructor generation. This could lead to memory leaks across the target

languages, and it is highly recommended you don’t use them

限制

虽然siwg能够处理大多数的C++语法,但swig并不是完整的C++解析器,仍然有很多的语法是swig无法解析的。

  • Non-conventional type declarations. For example, SWIG does not support declarations such as the following (even though this is legal C):
/* Non-conventional placement of storage specifier (extern) */
const int extern Number;
/* Extra declarator grouping */
Matrix (foo); // A global variable
/* Extra declarator grouping in parameters */
void bar(Spam (Grok)(Doh));

为C++的类添加成员函数

很多C类型的结构体是不能绑定成员函数的,但是其他函数中都能,为了提供便利swig支持为C类型的结构体绑定额外的成员函数用来辅助结构体的创建和使用,这时就要用到%extend指令了

/* file : vector.h */
...
typedef struct Vector {double x, y, z;
} Vector;

通过extend指令为C++类型的结构体添加构造函数

// file : vector.i
%module mymodule
%{#include "vector.h"
%}
%include "vector.h" // Just grab original C header file
%extend Vector { // Attach these functions to struct VectorVector(double x, double y, double z) {Vector *v;v = (Vector *) malloc(sizeof(Vector));v->x = x;v->y = y;v->z = z;return v;}~Vector() {free($self);}double magnitude() {return sqrt($self->x*$self->x+$self->y*$self->y+$self->z*$self->z);}void print() {printf("Vector [%g, %g, %g]\n", $self->x, $self->y, $self->z);}
};

但是extend指令只能用于struct上,不能用于经过typedef之后的类型名

typedef struct Integer {int value;
} Int;
%extend Integer { ... } /* Correct name */
%extend Int { ... } /* Incorrect name */
struct Float {float value;
};
typedef struct Float FloatValue;
%extend Float { ... } /* Correct name */
%extend FloatValue { ... } /* Incorrect name */

有一种特殊情况除外,那就是当typedef一个匿名类时,是可以使用extend的

typedef struct {double value;
} Double;
%extend Double { ... } /* Okay */

代码注入

swig代码输出格式

swig输出的C/C++代码会分为5部分

  • Begin section.

A placeholder for users to put code at the beginning of the C/C++ wrapper file. This is most often used to define preprocessor macros that are used in later sections.

  • Runtime code.

This code is internal to SWIG and is used to include type-checking and other support functions that are used by the rest of the module.

  • Header section.

This is user-defined support code that has been included by the %{ … %} directive. Usually this consists of header files and other helper functions.

  • Wrapper code.

These are the wrappers generated automatically by SWIG.

  • Module initialization.

The function generated by SWIG to initialize the module upon loading.

代码注入指令

命令注入格式:

// 将在section部分注入代码,section为begin runtime header wrapper init等字段
%insert("section") "filename"
// 将后面代码段的内容注入到指定段
%insert("section") %{ ... %}

当然除了使用insert指令,section名本身也是一种指令,也可以section作为指令的方式来对指定代码段进行代码注入

For example, %runtime is used instead of %insert(“runtime”).

%begin %{... code in begin section ...
%}
%runtime %{... code in runtime section ...
%}
%header %{... code in header section ...
%}
%wrapper %{... code in wrapper section ...
%}
%init %{... code in init section ...
%}

说明:其实经常使用的%{…%},其实是%header %{…%}的简写

The bare %{ … %} directive is a shortcut that is the same as %header %{ … %}

Init 段是给有些需要进行初始化的代码使用的。

辅助函数

实际使用中经常使用代码注入的功能来写辅助函数

%{/* Create a new vector */static Vector *new_Vector() {return (Vector *) malloc(sizeof(Vector));}
%}
// Now wrap it
Vector *new_Vector();

为了简化辅助代码的书写,引入了inline指令,该指令使用方式如下:

凡是被inline标记的代码段,相当于在代码和封装中都手写了一遍的效果:

%inline %{/* Create a new vector */
Vector *new_Vector() {return (Vector *) malloc(sizeof(Vector));
}
%}

等效于

%{/* Create a new vector */
Vector *new_Vector() {return (Vector *) malloc(sizeof(Vector));
}%
}
/* Create a new vector */
Vector *new_Vector() {return (Vector *) malloc(sizeof(Vector));
}

但是需要注意的是,inline只是对函数和变量有效,对于头文件的引用是否封装,还是需要原有的方式,在代码块中使用#include 引入头文件,而需要封装成目标代码的头文件需要在代码块外使用%include指令来告知swig需要对该头文件进行封装

说明:编译选项-Dmain=oldmain其实就是宏定义替换过程中使用,高速预处理器将main更换成等号后面的符号

对应视频课件: 【阿酷尔】swig教程_哔哩哔哩_bilibili
https://www.bilibili.com/video/BV19F411c7LM?spm_id_from=333.999.0.0&vd_source=d0f1fc53c13a7dcbda92faa2e368b71e

飞书文档
视频课件

SWIG教程-封装指令的使用《二》相关推荐

  1. SWIG教程-对C/C++语言的封装《三》

    使用SWIG对C++的封装 目前支持的C++特性 Classes Constructors and destructors Virtual functions Public inheritance ( ...

  2. 乐鑫esp8266学习rtos3.0笔记:AT指令固件如何二次开发,实现AT指令连接亚马逊AWS IoT平台;

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 基于C SDK的ESP8266开发技术全系列笔记 一.N ...

  3. 【Youtobe trydjango】Django2.2教程和React实战系列二【settings配置文件】

    [Youtobe trydjango]Django2.2教程和React实战系列二[settings配置文件] 1. Django项目初始化过程 2. 全貌 3. 详细解释 4. 增加其他配置 1. ...

  4. python基础代码库-python爬虫基础教程:requests库(二)代码实例

    get请求 简单使用 import requests ''' 想要学习Python?Python学习交流群:973783996满足你的需求,资料都已经上传群文件,可以自行下载! ''' respons ...

  5. python地理可视化_【Python教程】地理可视化之二

    Basemap是Matplotlib的一个子包,负责地图绘制.昨天的推送对如何绘制风向图进行了描述,本文再次利用该包简单介绍如何绘制海洋及海冰温度彩色图示,该图常见于NOAA官网.具体操作如下: 导入 ...

  6. Linux Shell脚本入门教程系列之(十二)Shell until循环

    本文是Linux Shell脚本系列教程的第(十二)篇,更多Linux Shell教程请看:Linux Shell脚本系列教程 在上两篇文章Linux Shell系列教程之(十)Shell for循环 ...

  7. python爬虫requests库_python爬虫基础教程:requests库(二)代码实例

    get请求 简单使用 import requests ''' 想要学习Python?Python学习交流群:973783996满足你的需求,资料都已经上传群文件,可以自行下载! ''' respons ...

  8. 【台大郭彦甫】Matlab入门教程超详细学习笔记二:基本操作与矩阵运算(附PPT链接)

    Matlab入门教程超详细学习笔记二:基本操作与矩阵运算 前言 一.基本操作 1.把matlab当作计算器使用 2.变量 3.控制格式输出 二.矩阵运算 1.矩阵 2.矩阵索引 3.使用:创建向量 4 ...

  9. CG基础教程-陈惟老师十二讲笔记

    转自 麽洋TinyOcean:http://www.douban.com/people/Tinyocean/notes?start=50&type=note 因为看了陈惟十二讲视频没有课件,边 ...

最新文章

  1. dvwa安装教程linux,Kali 2020.3安装docker和vulhub
  2. 如何解决failed to push some refs to git
  3. Jackson 注解 -- 使用 Map存储JSON
  4. 给指定服务器加路由,无线路由器如何给终端分配指定的IP地址?
  5. java 设置两个方法互斥_分享两个操作Java枚举的实用方法
  6. [深度学习-NLP]什么是Self-attention, Muti-attention和Transformer
  7. nginx学习(一):基本安装
  8. perl语言入门(7)
  9. erp服务器慢_ERP系统服务器维护经验谈
  10. 计算机音乐的制作流程,Premiere制作音乐电子相册的方法和流程 计算机类数媒...
  11. 以智能制造推动企业数字化转型的方法、路径和举措
  12. 加密狗Android软件,加密狗app
  13. thinkserver TS250安装centos7.5经验
  14. 分析:谷歌不会退出中国市场的8大理由
  15. 差异表达基因变化倍数_差异基因表达分析,如何寻找差异表达的基因?
  16. 现在,让客服接管数字化企业
  17. 只有360浏览器能打开别的都打不开
  18. python期货基本面分析_Python量化炒期货入门与实战技巧
  19. 文娱干货丨如何体系化构建优质社区氛围?
  20. matlab 显示表格化,[转载]matlab窗口中显示excel表格的问题

热门文章

  1. 360文件粉碎机_电脑文件删除不了怎么办
  2. Java Excel框架
  3. WeinView 与 MITSUBISHI FX 系列 PLC 通讯范例
  4. 罗斯蒙特404-11-16传感器
  5. 微信公众平台开发总结
  6. “借壳”上市成功,戴尔首日收涨2%
  7. c语言编程一个乘法scanf,几道简单的c语言编程题
  8. QQ2009下载地址泄密,QQ2009最新版
  9. linux内存耗尽实验,linux 内存耗尽的分析
  10. linux remount命令详解,linux mount命令参数及用法详解