Scilab is a scientific software package for numerical computations providing a powerful open computing environment for engineering and scientific applications that is mostly compatible with MATLAB. More information can be found at www.scilab.org.
This chapter explains how to use SWIG for Scilab. After this introduction, you should be able to generate with SWIG a Scilab external module from a C/C++ library.
SWIG for Scilab supports Linux. Other operating sytems haven't been tested.
Scilab is supported from version 5.3.3.
SWIG for Scilab supports C language. C++ is partially supported. See A basic tour of C/C++ wrapping for further details.
Let's show how to use SWIG for Scilab on a small example, inspired from the "simple" example (found in the Examples/scilab/simple directory).
We want to bind from C a function and a global variable into Scilab.
The SWIG interface (in example.i file) is as following:
%module Example
%{
double Foo = 3.0;
int gcd(int x, int y) {
int g;
g = y;
while (x > 0) {
g = x;
x = y % x;
y = g;
}
return g;
}
%}
/* A global variable */
double Foo;
/* Compute the greatest common divisor of positive integers */
int gcd(int x, int y);
Note: this is not the usual approach to write an interface file, it was used only for tightness and simplicity. See Module to see the usual way to write the interface file.
The module must be first generated, using the program swig and its -scilab option.
$ swig -scilab example.i
This command generates two files:
Note: if the following error is returned:
:1: Error: Unable to find 'swig.swg' :3: Error: Unable to find 'scilab.swg'
It may be because the SWIG library is not found. Check the SWIG_LIB environment variable or your SWIG installation.
The swig command line program has several other options you can use. See Additional command line options for further details.
Scilab external modules are shared libraries (with the .so file extension). Building such a file is usually done by running the builder.sce script in Scilab:
$ ./scilab-cli --> exec builder.sce
This command will produce two important files:
Note: two other files are generated:
This is done by running the following command in Scilab:
--> exec loader.sce
Scilab should output the following messages:
Shared archive loaded. Link done.
Which means that Scilab has sucessfully loaded the shared library. Its functions and other symbols are now available in Scilab.
In Scilab, the function gcd() can be used simply like that:
--> gcd(4,6) ans = 2
For the Foo global variable, the accessors have to be used:
--> Foo_get ans = 3 --> Foo_set(4); --> Foo_get ans = 4
The following table lists the specific options for Scilab (of swig program):
| -addcflag <opt> | Additional compiler options <opt> to include in build script |
| -addldflag <opt> | Additional link options <opt> to include in build script |
| -addsrc <files> | Additional comma separated source <files> to include in build script |
| -vbl <level> | Sets the build verbose <level> (default 0) |
| -buildflags <file> | Uses a Scilab script in <file> to set build flags level |
| -nobuilder | Do not generate builder script |
These options can be displayed with:
swig -scilab -help
Some examples:
$ swig -scilab -addcflag -I/usr/includes example.i $ swig -scilab -addldflag "-lm example.i" $ swig -scilab -addsrc file1.cxx,file2.cxx,example.i
SWIG for Scilab provides only low-level C interface only for Scilab. This means that functions, structs, classes, variables, etc... are interfaced through C functions. These C functions are mapped as Scilab functions.
In Scilab 5.x, identifier names can be composed of 24 chars maximum (this limitation disappears in future version of Scilab 6.0).
So long function or variables names can be truncated. It can be cause of conflict.
It happens especially when wrapping structs/classes, for which the wrapping functions name are composed of the struct/class name and field names. In that case, the SWIG rename instruction, to choose a different wrapping name, can be useful.
Global functions are wrapped as new Scilab built-in functions. For example:
%module example int fact(int n);
Creates a built-in function fact(n) that works exactly like you think it does:
--> fact(4) ans=24
The following table give for each C/C++ primitive type the equivalent Scilab type.
| C/C++ type | Scilab type |
| bool | boolean |
| char | string |
| signed char | double or int8 |
| unsigned char | uint8 |
| short | double or int16 |
| unsigned short | uint16 |
| int | double or int32 |
| unsigned int | uint32 |
| long | double or int32 |
| unsigned long | uint32 |
| signed long long | not supported with Scilab 5.x |
| unsigned long long | not supported with Scilab 5.x |
| float | double |
| double | double |
| char* or char[] | string |
Notes:
The default mapped type for C/C++ non-primitive types is the Scilab pointer. That is the case for exemple for C structs, C++ classes, ... But there are many type mappings for non-primitive types (such as enums, arrays, STL types, etc...). Each of them is described further in this document.
To expose variables, SWIG actually generates two functions, to get and set the value. In this case, Foo_set and Foo_get would be generated. SWIG then automatically calls these functions when you get and set the variable-- in the former case creating a local copy in the interpreter of the C variables, and in the latter case copying an interpreter variable value into the C variable.
--> exec loader.sce; --> c=Foo_get(); --> Foo_set(4); --> c c = 3 --> Foo_get() ans = 4
C constants are not really constant in Scilab. When dealing with the constants, a get function will be generated. For example given some constants:
%module example #define ICONST 42 #define FCONST 2.1828 #define CCONST 'x' #define CCONST2 '\n' #define SCONST "Hello World" #define SCONST2 "\"Hello World\""
It is easy to use them in Scilab:
--> exec loader.sce; --> ICONST_get(); ans= 42 --> FCONST_get(); ans= 2.1828 --> CCONST_get(); ans=x --> CCONST2_get(); ans= --> SCONST_get(); ans= Hello World --> SCONST2_get(); ans= "Hello World" --> EXPR_get(); ans= 48.5484 --> iconst_get(); ans= 37 --> fconst_get(); ans= 3.14
The way SWIG deals with the enums is similar to constants. For example:
%module example
typedef enum { RED, BLUE, GREEN } color;
Some code like RED_get(), BLUE_get(),GREEN_get() will be generated. It can be used as the following:
--> exec loader.sce;
--> printf(" RED = %i\n", RED_get());
RED = 0
--> printf(" BLUE = %i\n", BLUE_get());
BLUE = 1
--> printf(" GREEN = %i\n", GREEN_get());
GREEN = 2
Pointers are fully supported by SWIG. One way to deal with the pointers is using the INPUT and OUTPUT typemaps. For example, in order to call C functions as the following:
void sub(int *x, int *y, int *result) {
*result = *x - *y;
}
int divide(int n, int d, int *r) {
int q;
q = n/d;
*r = n - q*d;
return q;
}
We could write an interface file:
%module example
%include typemaps.i
extern void sub(int *INPUT, int *INPUT, int *OUTPUT);
%apply int *OUTPUT { int *r };
extern int divide(int n, int d, int *r);
Then run it in Scilab:
--> r = sub(37,42);
--> printf(" 37 - 42 = %i\n",r);
37 - 42 = -5
--> [q,r] = divide(42,37);
--> printf(" 42/37 = %d remainder %d\n",q,r);
42/37 = 1 remainder 5
From the example above, it is clear that instead of passing a pointer to an object, we only need a real value instead.
SWIG creates a set of accessor functions when encountering a structure or union. For example:
%module example
%inline %{
typedef struct {
int x;
} Foo;
%}
When wrapped, it would generate two main function: Foo_x_set(), which set the data value of the structure and Foo_x_get() which could obtain the value of the structure. Run it in Scilab:
--> a=new_Foo(); --> Foo_x_set(a,100); --> Foo_x_get(a) ans = 100
Arrays are fully supported by SWIG and Scilab. In SWIG, they are handled as pointers. It is easy to deal with arrays too. For example:
%module example
%inline %{
int x[10];
double y[7];
void initArray()
{
int i, n;
n = sizeof(x)/sizeof(x[0]);
for(i = 0; i > n; i++)
x[i] = i;
n = sizeof(y)/sizeof(y[0]);
for(i = 0; i < n; i++)
y[i] = ((double) i)/ ((double) n);
return;
%}
When wrapped, the following functions are generated: x_set(), x_get(), y_set(), y_get(), and _wrap_initArray. They can be used like this:
--> exec loader.sce --> initArray(); --> x_get() ans = 0 1 2 3 4 5 6 7 8 9 --> y_get() ans = 0. 0.1428571 0.2857143 0.4285714 0.5714286 0.7142857 0.8571429
Scilab uses matrices a lot for numerical mathematics and scientific visualization. Supporting matrices makes Scilab more convenient. For example:
%module example
%inline %{
double **new_matrix() {
int i;
double **M;
M = (double **) malloc(4 * sizeof(double *));
M[0] = (double *) malloc(16 * sizeof(double));
for (i = 0; i < 4; i++) {
M[i] = M[0] + 4 * i;
}
return M;
}
void set_m(double **M, int i, int j, double val) {
M[i][j] = val;
}
double get_m(double **M, int i, int j) {
return M[i][j];
}
void print_matrix(double **M) {
int i,j;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
printf("%10g ", M[i][j]);
}
printf("\n");
}
}
void mat_mult(double **m1, double **m2, double **m3) {
int i,j,k;
double temp[4][4];
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++) {
temp[i][j] = 0;
for (k = 0; k < 4; k++)
temp[i][j] += m1[i][k] * m2[k][j];
}
for (i = 0; i < 4; i++)
for (j = 0; j < 4; j++)
m3[i][j] = temp[i][j];
}
%}
When wrapped, it would generate the following function:
_wrap_new_matrix(): generate a new matrix.
_wrap_set_m(M, i, j, a): set M(i, j) to be value a.
_wrap_get_m(M, i, j): get the value of M(i, j).
_wrap_print_matrix(M): print the matrix M.
_wrap_mat_mult(A, B, C): compute the A * B and the result is stored into C.
It can be used like this:
--> exec loader.sce --> x = new_matrix(); --> for i = 0 : 3; --> for j = 0 : 3; --> set_m(x, i, j, i + j); --> end; --> end; --> print_matrix(y); 0 1 2 3 1 2 3 4 2 3 4 5 3 4 5 6 --> y = new_matrix(); --> for i = 0 : 3; --> for j = 0 : 3; --> set_m(y, i, j, i - j); --> end; --> end; --> print_matrix(y); 0 -1 -2 -3 1 0 -1 -2 2 1 0 -1 3 2 1 0 --> z = new_matrix(); --> mat_mult(x, y, z); --> print_matrix(z); 14 8 2 -4 20 10 0 -10 26 12 -2 -16 32 14 -4 -22
The classes are wrapped in the same manner as structs, through functions. For example, the following class:
class Point {
public:
int x,y;
Point(int _x,int _y) : x(_x),y(_y) {}
double distance(const Point& rhs) {
return sqrt(pow(x-rhs.x,2)+pow(y-rhs.y,2));
}
void set(int _x,int _y) {
x=_x; y=_y;
}
};
can be used from Scilab like this:
--> p1 = Point_new(3, 5);
--> p2 = Point_new(1, 2);
--> p1.distance(p2)
ans =
3.6056
Templates are supported. See the SWIG general documentation on how templates are interfaced in SWIG.
An example of templates can be found in Examples/scilab/templates.
Standard Template Library (STL) is partially supported.
The following containers are usable:
Each of these containers supports the following types:
Some typemaps between Scilab and STL are available.
A STL vector or list is mapped from/to a Scilab matrix or list, depending on type.
| STL type | Header 2 |
|---|---|
| vector/list of int | int matrix |
| vector/list of double | double matrix |
| vector/list of string | string matrix |
| vector/list of bool | bool matrix |
| vector/list of pointer | pointer list |
In the SWIG interface file, the STL support can be enabled with:
%include stl.i
As templates, for each specific type used, the STL container has the to be instantied:
namespace std {
%template(IntVector) vector;
%template(DoubleVector) vector;
At last, a command has to be run in Scilab, so that all that types are known by Scilab.
SWIG_Init();
In this part we describe how may be structured a module, how to build it, and give some details about the generated scripts.
Usually, one module is created to bind one library. Each library to be wrapped comes with the following files:
To one module corresponds one interface file. Multi modules in an interface file are not supported.
Usually the interface file will look like as following:
%module [module_name]
%{
#include [header]
....
%}
#include [header]
....
SWIG for Scilab builds dynamic modules. This means shared libaries are built (.so), which are dynamically linked by Scilab.
To generate the code and the builder script, the following options may be used with swig:
The swig command to use may be something like this:
swig -scilab -addcflag "-I[inc_path]..." -addsrc [source],... -addldflag "-L[lib_path] -l[lib_name]" [module_name].i
builder.sce is the script file generated by SWIG. It contains the following code:
ilib_name = "examplelib"; files = ["example_wrap.c"]; libs = []; table = ["gcd","_wrap_gcd";"Foo_set","_wrap_Foo_set";"Foo_get","_wrap_Foo_get";]; ilib_build(ilib_name,table,files,libs);
ilib_build(lib_name,table,files,libs) is used to create shared libraries and to generate a loader file which can be used to dynamically load the shared library into Scilab with addinter.
The loader script loader.sce script looks as following:
// ------------------------------------------------------
// generated by builder.sce: Please do not edit this file
// ------------------------------------------------------
libexamplelib_path = get_file_path('loader.sce');
list_functions = [ 'gcd';
'Foo_set';
'Foo_get';
];
addinter(libexamplelib_path+'/libexamplelib.so','libexamplelib',list_functions);
// remove temp. variables on stack
clear libexamplelib_path;
clear list_functions;
clear get_file_path;
// ------------------------------------------------------
addinter(files,spname,fcts) performs dynamic linking of a compiled C new Scilab interface routine.