Scilab Website | Contribute with GitLab | Mailing list archives | ATOMS toolboxes
Scilab Online Help
2024.1.0 - English


Getting started with API_Scilab

How to load a C, C++ or fortran code in the Scilab engine as a new function

Description

As described in the api_scilab presentation, Scilab offers an API to extend the language with C, C++ or Fortran code (sources or libraries).

The link between the Scilab engine and the application code is called gateway and have this prototype:

int your_new_gateway(scilabEnv env,
int nin, scilabVar *in,
int nopt, scilabOpt opt,
int nout, scilabVar *out)
  • env: scilabEnv variable provided by kernel. You must forward it to API functions.

  • nin: number of input arguments.

  • in: array of scilabVar containing input parameters.

  • nopt: number of optional parameters.

  • opt: scilabOpt containing optional parameters. Use scilab_getOptional to get optional information.

  • nout: number of expected output parameters.

  • out: preallocated array of scilabVar with a size of nout.

Return 0 or STATUS_OK for OK and other value or STATUS_ERROR to trigger an error.

Most of the time, the process is always the same:

  1. Check the number of arguments (both input and output) provided by the user.

    For example, if the function foo(x) is called with foo() or foo(2,3), the user must get an answer.

  2. Manage input arguments

    Several tasks are performed:

    1. Check the type of the variable: matrix of double (complex or not), string, etc with scilab_getType

      Other functions are also provided:

    2. If it is relevant, check if the input argument is complex or not with scilab_isComplex

    3. Dealing with integer, further checks should be done on the precision of the integer with scilab_getIntegerPrecision

    4. Check the dimensions of the variable: square matrix, scalar, etc

      Almost all Scilab datatypes have an equivalent C function to perform such task.

    5. Other checks can be done like specific values expected, consistency between the first and second input arguments, etc.

    6. Data transformation (optional).

      Depending on the code or library targeted, some transformations can be applied to the data. A classical example is changing the storage of a matrix from column-stored to line-stored.

      Please note that it is usually a performance killer.

  3. Application code

    Once all the checks and data retrieval have been performed, the actual core code can be called. The actual intelligence (processes, data transformations, etc) will be performed here.

    This can be done through a thirdparty code stored and built in src/c, src/cpp or src/fortran but also under the form of a library. Virtually, any library could be linked to Scilab.

  4. Create the output arguments for the Scilab engine

    Once the application code has been executed, usually, some data will be returned to the Scilab interpreter.

    For example, to create in the Scilab engine memory a matrix of double, the C function scilab_createDoubleMatrix should be called.

By default, Scilab numerical values are stored with the C type double.

As convention, gateways are stored in sci_gateway/c/ (or /cpp/) and are called sci_functionName.c.

Real life example

Taking the sample Scilab function:

[c,d] = foo(a,b)

with a being a matrix of double and b a matrix of boolean with the same size of a, foo will multiply each element of a by 2 and return it as c and transform each element of element of b to its opposite.

The example is available in the toolbox skeleton provided with the Scilab binary. The path is contrib/toolbox_skeleton/sci_gateway/c/sci_foo6.c

Detailed explanations are provided under the form of C comment in the following example.

// Full source can be found in the sci_gateway/c/ directory of the toolbox skeleton

#include "api_scilab.h"
#include "Scierror.h"
#include "BOOL.h"
#include "localization.h"

static const char fname[] = "foo6";
/* ==================================================================== */
int sci_foo6(scilabEnv env, int nin, scilabVar* in, int nopt, scilabOpt* opt, int nout, scilabVar* out)
{
    int i = 0;
    int row1 = 0;
    int col1 = 0;
    int size1 = 0;
    double* in1 = NULL;
    double* out1 = NULL;

    int row2 = 0;
    int col2 = 0;
    int size2 = 0;
    int* in2 = NULL;
    int* out2 = NULL;

    /* --> [a,b] = foo(d[i,j], b[i,j])
    /* check that we have only 2 input arguments */
    /* check that we have only 1 output argument */
    if (nin > 2)
    {
        Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), fname, 2);
        return 1;
    }

    if (scilab_isDouble(env, in[0]) == 0 || scilab_isMatrix2d(env, in[0]) == 0 || scilab_isComplex(env, in[0]) == 1)
    {
        Scierror(999, _("%s: Wrong type for input argument #%d: A scalar expected.\n"), fname, 1);
        return 1;
    }

    if (scilab_isBoolean(env, in[1]) == 0 || scilab_isMatrix2d(env, in[1]) == 0)
    {
        Scierror(999, _("%s: Wrong type for input argument #%d: A boolean matrix expected.\n"), fname, 2);
        return 1;
    }

    size1 = scilab_getDim2d(env, in[0], &row1, &col1);
    size2 = scilab_getDim2d(env, in[1], &row2, &col2);

    if (row1 != row2 || col1 != col2)
    {
        Scierror(999, _("%s: Wrong size for input arguments: Same size expected.\n"), fname);
        return 1;
    }

    scilab_getDoubleArray(env, in[0], &in1);
    scilab_getBooleanArray(env, in[1], &in2);

    out[0] = scilab_createDoubleMatrix2d(env, row1, col1, 0);
    out[1] = scilab_createBooleanMatrix2d(env, row2, col2);

    scilab_getDoubleArray(env, out[0], &out1);
    scilab_getBooleanArray(env, out[1], &out2);

    for (i = 0; i < size1; ++i)
    {
        //For each element of the matrix, multiply by 2
        out1[i] = in1[i] * 2;
    }

    for (i = 0; i < size2; ++i)
    {
        //For each element of the matrix, invert the value
        out2[i] = in2[i] == TRUE ? FALSE : TRUE;
    }

    return 0;
}

To build this code and load it to Scilab, we use the dynamic link capabilities of Scilab. Delegating the build process to Scilab, this code is multiplaform.

files=["sci_foo6.c"];
ilib_build('build_lib',['foo6','sci_foo6','csci6'],files,[]);
exec loader.sce
[c, d] = foo6([2,%pi], [%t, %f])

Various checks can be performed:

--> [c, d] = foo6(2, 2)

foo6: Wrong type for input argument #2: A boolean matrix expected.
-->[c, d] = foo6([2,2], %t)
                        !--error 999
foo6: Wrong size for input arguments: Same size expected.
-->[a,b]=foo6(2+%i,%t)
                   !--error 999
foo6: Wrong type for input argument #1: A real matrix expected.
-->[c, d] = foo6([2,%pi], [%t, %f])
 d  =

  F T
 c  =

    4.    6.2831853

Report an issue
<< API Scilab API Scilab API common functions >>

Copyright (c) 2022-2024 (Dassault Systèmes)
Copyright (c) 2017-2022 (ESI Group)
Copyright (c) 2011-2017 (Scilab Enterprises)
Copyright (c) 1989-2012 (INRIA)
Copyright (c) 1989-2007 (ENPC)
with contributors
Last updated:
Mon Jun 17 17:49:22 CEST 2024