howto/Create a toolbox - Scilab Wiki

This article describes a standard method to create a Scilab toolbox. The objective is to help the contributors to build a toolbox easily, but also that the users are able to install it just by executing a main builder and a main loader script. We show in first time how to structure your toolbox (sub-directories contents, files, ...), in second time how to customize the templates to create the builder(s), the loader(s), and the Scilab help files. To finish we explain how to upload your contribution on the Scilab website. For this article the reference toolbox name is toolbox_skeleton.

You can find a template of toolbox in SCI/contrib/toolbox_skeleton/. To get this example on Windows, you must install "A toolbox skeleton (to extend Scilab)" component when you install Scilab.

Definitions

Script

Scilab scripts are text files with the extension .sce. They are used to store Scilab code which can be executed using the exec function.

Macros

Scilab macros are Scilab functions written in Scilab code and stored in a file with the extension .sci.

Primitive

Scilab primitives are Scilab functions which call a function written in C, C++ or fortran code, using an interface (gateway) program. So for each Scilab primitive we must create the corresponding interface program.

Builder

A builder file is a Scilab script used to build the toolbox i.e. to create a binary version which Scilab can load from a source version. This file is called builder*.sce (Examples: builder.sce, buildhelp.sce, ...).

Loader

A loader file is a Scilab script used to load the toolbox in Scilab. This file is called loader*.sce (Examples: loader.sce, loadhelp.sce, ...).

Toolbox structure

The root directory has the generic name of the toolbox (here toolbox_skeleton), it contains 8 sub-directories:

and 4 files:

To build this toolbox, you have to run this command in Scilab:

exec builder.sce

And then run the loader to load/launch the toolbox:

exec loader.sce

Then you can launch Scilab help browser to see the help pages about toolbox_skeleton:

help

Sub-builders and sub-loaders

The main builder and main loader scripts launch respectively the sub-builders and sub-loaders included in the sub-directories (macros, src, help, ...), to generate and load needed libraries and Scilab help files.

The macros directory

By convention the builder included in the macros directory is named buildmacros.sce.

In this example, we consider that the macros directory of the toolbox_skeleton toolbox contains just only one macro, the function scilab_sum (see above script). This function returns s the sum of A + B (A and B are the inputs of the function).

Example of Scilab macro: scilab_sum.sci

function s = scilab_sum(A, B)
  s = A + B;
endfunction

The macros builder

The builder (see below script) creates a library variable from macros stored in the directory macros, and saves it in the file calledlib. The builder file contents is generic, it is executed in two steps:

The library generated is called: toolbox_skeletonlib i.e. yourtoolboxnamelib (yourtoolboxname must be 21-characters long max).

Contents of buildmacros.sce file:

tbx_build_macros(TOOLBOX_NAME, get_absolute_file_path('buildmacros.sce'));

clear tbx_build_macros;

The macros loader

The loader loads the library generated by the builder in the directory macros.

src and sci_gateway directories

As said before, a Scilab primitive is a Scilab function which calls a function written in C/C++ or fortran code through an interface. So for each Scilab primitive we must create the corresponding interface program stored in the sci_gateway directory. The source code of the function is stored in the src directory and its sub-directories (c, cpp, fortran, ...).

C/Scilab Interface

When a Scilab primitive is called, the interface program checks that the number, the type and the size of inputs/outputs arguments is correct (using functions such as CheckRhs and CheckLhs), and gets the input argument addresses which are in Scilab internal stack to give this information to the interfaced function.

We won't describe here all the possibilities of interface programs, for more explanations see the directory SCI/dynamic_link/examples.

Example of interface program

These examples (written in C code) are described step by step. They explain how to write interfaces, so it's important to understand them to know how to customize them for your toolboxes.

First example: C function

We consider a C function csum which returns the sum of two scalars. We suppose that the name of the corresponding primitive in Scilab is c_sum and the associated interface program name is sci_csum. By convention all interface program names begin with "sci_". The both following scripts represent the C code of csum and sci_csum.

The primitive c_sum can be called in Scilab as follows:

--> Y = c_sum(A,B)

Source code of csum.c:

int csum(double *a, double *b, double *c)
{
        *c = *a + *b;
        return 0;
}

Source code of sci_csum.c:

#include "stack-c.h"
/* ==================================================================== */
extern int csum(double *a,double *b,double *c);
/* ==================================================================== */
int sci_csum(char *fname)
{
  int l1, m1, n1, l2, m2, n2, m3, n3,l3;

  double a,b,c;

  a = 0;
  b = 0;
  c = 0;

  /* --> result = csum(3,8)
  /* check that we have only 2 parameters input */
  /* check that we have only 1 parameters output */
  CheckRhs(2,2) ;
  CheckLhs(1,1) ;

  /* get first parameter and put in 'a' */
  GetRhsVar(1, MATRIX_OF_DOUBLE_DATATYPE, &m1, &n1, &l1);
  a = *stk(l1);

  /* get second parameter and put in 'a' */
  GetRhsVar(2, MATRIX_OF_DOUBLE_DATATYPE, &m2, &n2, &l2);
  b= *stk(l2) ;

  /* call csum subroutine */
  csum(&a,&b,&c);

  /* create a variable on scilab's stack */
  m3=1;
  n3=1;
  CreateVar(Rhs+1,MATRIX_OF_DOUBLE_DATATYPE,&m3,&n3,&l3);
  *stk(l3) = c;

  LhsVar(1) = Rhs+1;
  return 0;
}

Step 1: CheckRhs(minrhs,maxrhs) and CheckLhs(minlhs,maxlhs) instructions

CheckRhs function uses the arguments minrhs and maxrhs to check that:

The number of inputs and outputs arguments (respectively 2 and 1) of csum are constant, so minrhs=maxrhs=2 and minlhs=maxlhs=1, but for other functions they can be variable, in this case the variables minrhs/minlhs and maxrhs/maxlhs are different.

We can use directly the defined variables Rhs (number of inputs) and Lhs (number of outputs) instead of the functions CheckRhs and CheckLhs to check the number of inputs/outputs.

Step 2: GetRhsVar(1,MATRIX_OF_DOUBLE_DATATYPE,&m1,&n1,&l1) instruction

GetRhsVar function checks that the type of inputs arguments of c_sum are correct, and gets their size and address in Scilab stack. We describe below all arguments of GetRhsVar function:

Step 3: csum(&a,&b,&c) instruction

Call to the C function csum which returns in c the sum of a and b.

Step 4: CreateVar(Rhs+1,MATRIX_OF_DOUBLE_DATATYPE,&m3,&n3,&l3) instruction

CreateVar function creates in the stack at the Rhs+1 th position a variable which corresponds to the output argument of csum. Here is a description of CreateVar function arguments:

Step 5: LhsVar(1) = Rhs+1 instruction

The first output argument (here Y) of c_sum takes the value of the variable placed in the Rhs+1 th position on the stack (i.e stk(l3)).

Second example: fortran function

We consider an fortran subroutine fsum which returns the sum of two scalars. We suppose that the name of the corresponding primitive in Scilab is fortran_sum and the associated interface program name is sci_fsum. By convention all interface program names begin by "sci_". The both following scripts represent the fortran code of fsum and sci_fsum.

The primitive fortran_sum in can be called in Scilab as follows:

--> Y = fortran_sum(A,B)

Source code of fsum.f:

c =================================
      subroutine fsum(a,b,c)
c =================================
      double precision a,b,c
                        c = a + b
      end
c =================================


Source code of sci_fsum.c (we call a fortran subroutine from a C gateway):

#include "stack-c.h"
/* ==================================================================== */
extern int F2C(fsum)(double *a,double *b,double *c);
/* ==================================================================== */
int sci_fsum(char *fname)
{
  int l1, m1, n1, l2, m2, n2, m3, n3,l3;

  double a,b,c;

  a = 0;
  b = 0;
  c = 0;

  /* --> result = fortran_sum(3,8)
  /* check that we have only 2 parameters input */
  /* check that we have only 1 parameters output */
  CheckRhs(2,2) ;
  CheckLhs(1,1) ;

  /* get first parameter and put in 'a' */
  GetRhsVar(1, MATRIX_OF_DOUBLE_DATATYPE, &m1, &n1, &l1);
  a = *stk(l1);

  /* get second parameter and put in 'a' */
  GetRhsVar(2, MATRIX_OF_DOUBLE_DATATYPE, &m2, &n2, &l2);
  b= *stk(l2) ;

  /* call fortran fsum subroutine */
  F2C(fsum)(&a,&b,&c);

  /* create a variable on scilab's stack */
  m3=1;
  n3=1;
  CreateVar(Rhs+1,MATRIX_OF_DOUBLE_DATATYPE,&m3,&n3,&l3);
  *stk(l3) = c;

  LhsVar(1) = Rhs+1;
  return 0;
}

This function is very similar to sci_csum.c

Primitives builder

Now the src and the sci_gateway directories contain all necessary files to create the builder (see template below) for the primitive c_sum.

We need to write two builders:

Contents of builder_c.sce file:

tbx_build_src(['csum','csub'], ['csum.o','csub.o'], 'c', ..
              get_absolute_file_path('builder_c.sce'));

clear tbx_build_src;

Contents of buildsci_gateway.sce file:

tbx_build_gateway('skeleton_c', ['c_sum','sci_csum';'c_sub','sci_csub'], ['sci_csum.o','sci_csub.o'], ..
                  get_absolute_file_path('builder_gateway_c.sce'), ..
                  ['../../src/c/libcsum']);

clear tbx_build_gateway;

The help directory

This directory contains .xml files and a builder_help.sce script.

Creation of .xml files

Here is a template which shows you how to write the .xml help files. You should just fill the different items for your functions and put them in the help directory.

See http://wiki.scilab.org/howto/scilab_documentation_kit for more information about documentation.

Example of Scilab help file, c_sum.xml:

<?xml version="1.0" encoding="UTF-8"?>
<refentry version="5.0-subset Scilab" xml:id="c_sum" xml:lang="en"
          xmlns="http://docbook.org/ns/docbook"
          xmlns:xlink="http://www.w3.org/1999/xlink"
          xmlns:svg="http://www.w3.org/2000/svg"
          xmlns:ns3="http://www.w3.org/1999/xhtml"
          xmlns:mml="http://www.w3.org/1998/Math/MathML"
          xmlns:db="http://docbook.org/ns/docbook">
  <info>
    <pubdate>$LastChangedDate: 2008-03-26 09:50:39 +0100 (mer., 26 mars 2008)$</pubdate>
  </info>

  <refnamediv>
    <refname>c_sum</refname>

    <refpurpose>sum from C</refpurpose>
  </refnamediv>

  <refsynopsisdiv>
    <title>Calling Sequence</title>

    <synopsis>a = c_sum(b,c)</synopsis>
  </refsynopsisdiv>

  <refsection>
    <title>Description</title>

    <para>Do a sum.</para>

    <para>Add here a paragraph of the function description </para>
  </refsection>

  <refsection>
    <title>Examples</title>

    <programlisting role="example">c_sum(3,4)</programlisting>
  </refsection>

  <refsection>
    <title>Authors</title>

    <simplelist type="vert">
      <member>YOUR NAME</member>
    </simplelist>
  </refsection>
</refentry>

The help builder

This file creates a file containing all your toolbox documentation so that it can be loaded in Scilab help browser.

Contents of build_help.sce:

help_lang_dir = get_absolute_file_path('build_help.sce');

tbx_build_help(TOOLBOX_TITLE, help_lang_dir);

clear help_lang_dir;

The main builder

This builder is generic, it executes all sub-builder(s), here is its contents:

mode(-1);
lines(0);
try
 getversion('scilab');
catch
 error(gettext('Scilab 5.0 or more is required.'));
end;
// ====================================================================
if ~with_module('development_tools') then
  error(msprintf(gettext('%s module not installed.'),'development_tools'));
end
// ====================================================================
TOOLBOX_NAME = 'toolbox_skeleton';
TOOLBOX_TITLE = 'Toolbox Skeleton';
// ====================================================================
toolbox_dir = get_absolute_file_path('builder.sce');

tbx_builder_macros(toolbox_dir);
tbx_builder_src(toolbox_dir);
tbx_builder_gateway(toolbox_dir);
tbx_builder_help(toolbox_dir);
tbx_build_loader(TOOLBOX_NAME, toolbox_dir);

clear toolbox_dir TOOLBOX_NAME TOOLBOX_TITLE;
// ====================================================================

Upload your toolbox

Now your toolbox can be compiled and loaded, you can:

howto/Create a toolbox (last edited 2009-06-25 15:10:38 by couvert)