当前位置:网站首页>SWIG tutorial "two"

SWIG tutorial "two"

2022-08-10 14:54:00 Ah cool studio

变量属性

使用immutableCreate read-only fields,Variables edited using this field have only counterparts in the corresponding target languageGetX接口,无法对值进行修改.

A variable is once marked as immutable之后,Only explicitly re-specified asmutable,Otherwise it is always a read-only variable

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

重命名

Sometimes when converting the corresponding language to the target language,due to different keywords,Variables that work normally in that language may be keywords in the target language,这个时候可以使用rename进行重命名.

// interface.i
// will be in the source languageprint函数重命名为my_printThis will pass in the target languagemy_printto call in the source languageprint
%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;

renameThe scope is from the beginning of the declaration until the end of the file,So if you want that header file to be renamed, you need to ensure that the header file is importedrename之后

%rename(my_print) print;
%rename(foo) a_really_long_and_annoying_name;
%include "header.h"
// It doesn't matter if you add double quotes or not,But when the renamed name isC++的关键字是,Adding double quotes becomes necessary
%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()

Being able to name a single one is usually enough,但swig的功能远不止于此,Batch naming can be done by matching,Such as adding a prefix to all functions

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

Modify all snake case names to camel case names

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

Eliminate some characters in the name from being used

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

Rename operator overloaded functions

%rename(__add__) Complex::operator+;

If operator overloading is required for friend function or global function overloading, it is renamed as follows

%rename(op_j) ::operator+;

It also supports matching using regular expressions

// 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可以指示swigIgnore things that don't need encapsulation

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

You can choose to ignore most symbols,Only a small part of it is encapsulated

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"

It can also be ignored by type

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

回调函数

Some functions that need to be passed a callback,需要提前声明,The function implemented by the target function cannot be passed in directly

/* Function with a callback */
int binary_op(int a, int b, int (*op)(intint));
/* Some callback functions */
// Pass in the callback function to be used
%constant int add(intint);
%constant int sub(intint);
%constant int mul(intint);

Once declared as a callback function,Will not be used as a normal function in the target function,If a function is called as a callback function, it also wants to be called as a normal function,It can be declared as follows

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

Structure and Analysis

Swig 为每个C++The class generates default constructors and parsing functions,If it is not needed, it can be disabled using parameter options or directives

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

Or you can be more precise to specify which class does not create a constructor

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

虽然,Not creating an analysis function often results in memory leaks,但是swigStill allows you to control not to create the parsing function throughnodefaultdtorSpecifies the type that does not require a parsing function

%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

限制

虽然siwgCan handle most of themC++语法,但swig并不是完整的C++解析器,There is still a lot of syntax that isswig无法解析的.

  • 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++The class adds member functions

很多CA struct of type cannot bind member functions,But in other functions,For convenienceswig支持为CTyped structures bind additional member functions to aid in the creation and use of structures,这时就要用到%extend指令了

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

通过extend指令为C++Add a constructor to a type of struct

// file : vector.i
%module mymodule
%{
#include "vector.h"
%}
%include "vector.h" // Just grab original C header file
%extend Vector { // Attach these functions to struct Vector
    Vector(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上,Cannot be used for passingtypedefafter the type name

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 */

有一种特殊情况除外,那就是当typedefan anonymous class,是可以使用extend的

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

代码注入

swig代码输出格式

swig输出的C/C++The code will be divided into5部分

  • 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.

Code injection instructions

Command injection format:

// 将在sectionPartially injected code,section为begin runtime header wrapper init等字段
%insert("section""filename"
// Injects the content of the following code segment into the specified segment
%insert("section") %{ ... %}

当然除了使用insert指令,sectionThe name itself is also an instruction,也可以sectionAs an instruction, code injection is performed on the specified code segment

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 ...
%}

说明:Actually used often%{....%},其实是%header %{...%}的简写

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

Init Sections are used by some code that needs to be initialized.

辅助函数

In actual use, the function of code injection is often used to write auxiliary functions

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

In order to simplify the writing of auxiliary code,引入了inline指令,The command is used as follows:

凡是被inline标记的代码段,It is equivalent to the effect of writing it by hand in both the code and the package:

%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));
}

但是需要注意的是,inlineOnly valid for functions and variables,Whether references to header files are encapsulated,Still need the original way,在代码块中使用#include 引入头文件,The header files that need to be encapsulated into object code need to be used outside the code block%includeinstruction to informswigThis header file needs to be encapsulated

说明:编译选项-Dmain=oldmainIn fact, it is used in the macro definition replacement process,A high-speed preprocessor willmainReplace it with the symbol after the equals sign

原网站

版权声明
本文为[Ah cool studio]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/222/202208101431161905.html