So_penible_animation
2004
Le but de ce tutorial est de montrer comment construire et interfacer
du code C pour l'utiliser avec Scilab.
Les interfaces sont écrites à la main en début du code C.
On va présenter deux exemples triviaux. Le premier fait
la somme de deux entiers et renvoie le résultat. Le second permet
d'utiliser de manipuler des matrices de Scilab au code C et
réciproquement (fonctions ReadMatrix et WriteMatrix), ce
qui est intéressant pour pouvoir tirer parti des avantages de chaque
environement : calcul et représentation matricielle sous Scilab (pas
de pointeurs ;-P), rapidité du code C.
Présentons d'abord le premier programme interface_ma_fonction_C.c
#include <stdio.h>
#include <math.h>
#include "/usr/lib/scilab-3.0/routines/machine.h"
#include "/usr/lib/scilab-3.0/routines/stack-c.h"
/*--------------------------------------------------------
* interface_ma_fonction_C: interface for tutorial C-function
* should provide a+b at Scilab level
*--------------------------------------------------------*/
extern void F2C(ma_fonction_C) __PARAMS((int *a, int *b, int *resultat));
void interface_ma_fonction_C(fname)
char *fname;
{
int l1,mi,ni,l2,mj,nj,l3,msortie=1,nsortie=1;
int minlhs=1, maxlhs=1, minrhs=2, maxrhs=2;
/* Check number of inputs (rhs=2) and outputs (lhs=1) */
CheckRhs(minrhs,maxrhs) ;
CheckLhs(minlhs,maxlhs) ;
GetRhsVar(1, "i", (mi=1,&mi), (ni=1,&ni), &l1); // a
GetRhsVar(2, "i", (mj=1,&mj), (nj=1,&nj), &l2); // b
CreateVar(3, "i",&msortie, &nsortie, &l3); // resultat
/* Call the function */
C2F(ma_fonction_C)(istk(l1),istk(l2),istk(l3));
/* Return variables */
LhsVar(1) = 3;
return 0;
}
//----------------------------------------------------------------------------------------------------
///////////////////// Fin de l'interface -------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//***** Debut du programme ****//
void F2C(ma_fonction_C)(astar,bstar,resultatstar)
int *astar,*bstar,*resultatstar;
{
resultatstar[0]=astar[0]+bstar[0];
// printf(" calcul fait resultat= %d",resultatstar[0]); /// les printfs s'affichent dans le terminal ///
return(0);
}
Pour la partie interface, on constate que les variables sont
passées sous forme de pointeurs. On doit vérifier le nombre et la
taille des variables d'entrée et de sortie CheckRhs,
CheckLhs, GetRhsVar, CreateVar (les paramètres associés sont
des paramètres de type, de taille (ligne et colonne) et d'adresse. Le résultat est désigné en
précisant le numéro de la variable de sortie LhsVar(1) =
3. L'appel de la fonction fait intervenir le type de la variable
par le biais de istk(adresse) pour des entiers (sstk
pour des floats) associé respectivement à ``i'' dans le
GetRhsVar (``r'' pour les floats).
Le second programme est structurellement identique sauf qu'il ne renvoie pas de résultat. Il permet cependant d'utiliser des fonctions permettant de lire ou d'écrire une matrice directement dans Scilab.
#include <stdio.h>
#include <math.h>
#include "/usr/lib/scilab-3.0/routines/machine.h"
#include "/usr/lib//scilab-3.0/routines/stack-c.h"
/*--------------------------------------------------------
* interface_ma_fonction_C2: interface for tutorial C-function
*
*--------------------------------------------------------*/
extern void F2C(ma_fonction_C2b) __PARAMS((int *a, int *b, int *taille));
void interface_ma_fonction_C2b(fname)
char *fname;
{
int l1,mi,ni,l2,mj,nj,l3,mk,nk,l4,msortie=1,nsortie=1;
int minlhs=0, maxlhs=0, minrhs=3, maxrhs=3;
/* Check number of inputs (rhs=3) and outputs (lhs=0) */
CheckRhs(minrhs,maxrhs) ;
// CheckLhs(minlhs,maxlhs) ; // not needed here (because no output)
GetRhsVar(1, "i", (mi=1,&mi), (ni=1,&ni), &l1); // a
GetRhsVar(2, "i", (mj=1,&mj), (nj=1,&nj), &l2); // b
GetRhsVar(3, "i", (mk=1,&mk), (nk=1,&nk), &l3); // taille
/* Call the function */
C2F(ma_fonction_C2b)(istk(l1),istk(l2),istk(l3));
return(0);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////// Fin de l'interface ////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////
//**** Debut du programme ****//
#include <stdio.h>
#include <math.h>
#include "/usr/lib/scilab-3.0/routines/machine.h"
#include "/usr/lib/scilab-3.0/routines/stack-c.h"
void F2C(ma_fonction_C2b)(astar,bstar,taillestar)
int *astar,*bstar,*taillestar;
{
int taille,*resultatstar;
taille=taillestar[0];
double NEWMATRICE[taille][taille];
resultatstar[0]=astar[0]+bstar[0];
// Lecture de la matrice "NEWMATRICE" dans l'environement Scilab
ReadMatrix("NEWMATRICE",&taillestar[0], &taillestar[0], &NEWMATRICE[0][0]);
NEWMATRICE[0][0]=4; // modification d'une donnee
// Ecriture de la matrice NEWMATRICE2 dans l'environement Scilab (qui a pour valeur NEWMATRICE modifiee
WriteMatrix("NEWMATRICE2", &taillestar[0], &taillestar[0], &NEWMATRICE[0][0]);
return(0);
}
Maintenant la compilation :
On execute dans Scilab le programme builder.sce qui contient :
// This is the builder.sce
// must be run from this directory
ilib_name = 'libtutorial' // interface library name
files = ['interface_ma_fonction_C.o','interface_ma_fonction_C2b.o'] // objects files
//
libs = [] // other libs needed for linking
table = [ 'ma_fonction_C', 'interface_ma_fonction_C';
'ma_fonction_C2b', 'interface_ma_fonction_C2b']; // table of (scilab_name,interface-name)
// for fortran coded interface use 'C2F(name)'
// do not modify below
// ----------------------------------------------
ilib_build(ilib_name,table,files,libs)
Si tout se passe bien on a
-->exec builder.sce;
ilib_name =
libtutorial
files =
!interface_ma_fonction_C.o interface_ma_fonction_C2b.o !
libs =
[]
generate a gateway file
generate a loader file
generate a Makefile: Makelib
running the makefile
compilation of interface_ma_fonction_C
compilation of interface_ma_fonction_C2b
building shared library (be patient)
Un certain nombre de fichiers ont été générés
interface_ma_fonction_C2b.lo interface_ma_fonction_C2b.o interface_ma_fonction_C.lo interface_ma_fonction_C.o .libs libtutorial.so libtutorial.a libtutorial.c loader.sce Makelib
Le plus important est le loader.sce qui va nous permettre déxecuter les fonctions son contenu est le suivant :
// generated by builder.sce: Please do not edit this file
// ------------------------------------------------------
libtutorial_path=get_file_path('loader.sce');
functions=[ 'ma_fonction_C';
'ma_fonction_C2b';
];
addinter(libtutorial_path+'/libtutorial.so','libtutorial',functions);
Le programme Scilab proprement dit :
// Ce programme Scilab permet d'utiliser des fonctions C
// interface_ma_fonction_C.c et interface_ma_fonction_C2.c
/// Chargement
exec loader.sce; /// affiche : --> shared archive loaded
a=2;
b=3;
/// 1er exemple
/// Appel de ma_fonction_C
resu=ma_fonction_C(a,b) // donne 5 ;-)
/// 2eme exemple
NEWMATRICE=ones(2,2); // creation d'une matrice 2x2 contenant des 1
taille=2; // taille de la matrice
/// Appel de ma_fonction_C2b
ma_fonction_C2b(a,b,taille); // les variables a et b ne servent a
rien ici !!!
/// on verifie que dans Scilab une nouvelle matrice NEWMATRICE2 a ete creee
/// et qu'elle contient un 4 et trois 1
\\fin du programme
En conclusion, ce n'est pas si difficile à faire que d'utiliser du
code C dans scilab. L'écriture manuelle des interfaces n'est pas très difficile
à condition cependant de bien sentir comment les choses
fonctionnent car les exemples donnés ne sont pas si explicite que ça ! Le reproche que je peux adresser sur ce point à Scilab est
par exemple de
ne pas décrire comment utiliser un appel d'une fonction C dans une
autre fonction C, même si en trifouillant un peu on arrive à faire
une fonction récursive (factorielle)1 . D'autres parts la
multiplicité des méthodes diverses intersci, ... et le
peu de documentation sont un gros manque.
Voilà,
That's all, Folks !