# Introduction

Ce didacticiel est destiné aux utilisateurs maîtrisant la programmation en C ou C++, ainsi que l'architecture de la Simple Virtual Machine.

Dans ce didacticiel, vous allez découvrir l'outil de génération d'extension de la machine virtuelle.

Le temps de lecture de ce didacticiel est estimé à 15 minutes.

# Mise en place

Pour commencer, créez le canevas de l'application dans le fichier exécutable generation.svm en utilisant ce code :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin generation exploration
    END
    LOG
    DEBUG "Plugin generation"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    	END
    END

# Génération d'une extension

## Ecriture de l'extension

L'écriture d'une extension de la Simple Virtual Machine peut très bien se faire sans outil particulier, mais cela n'est recommandé que pour ses vertus d'apprentissage profond.

Ici, nous allons plutôt employer un outil (fourni avec la machine virtuelle) permettant de faciliter et raccourcir l'écriture des extensions.

Dans le même répertoire que le fichier generation.svm, ouvrez un autre fichier generation.svm_plugin avec votre éditeur de texte préféré, puis ajoutez-y ce code :

    PLUGIN generation

    DEFINE

    TYPE generation.counter
    %{
    	explicit type_counter(const size_t l)
    	:_counter(0), _limit(l) {}
    	type_counter(const type_counter& c)
    	:_counter(c._counter), _limit(c._limit) {}
    	operator std::string () const
    	{
    		std::ostringstream oss;
    		oss << _counter << "/" << _limit;
    		return oss.str();
    	}
    	size_t _counter;
    	size_t _limit;
    %}
    delete default: %{}
    copy default: %{}
    print default: %{}

    INSTRUCTION generation.new INT -> generation.counter
    %{
    	auto l = ARGV_VALUE(0,integer);
    	if(l<0)
    	{
    		ERROR_INTERNAL(NUMERIC,"Invalid limit");
    	}
    	return NEW_PLUGIN(generation,counter,new type_counter(static_cast<size_t>(l)));
    %}

    INSTRUCTION generation.touch MUTABLE generation.counter
    %{
    	auto c = ARGV_PLUGIN(0,generation,counter);
    	++c->_counter;
    %}

    INSTRUCTION generation.check generation.counter -> BLN
    %{
    	auto c = ARGV_PLUGIN(0,generation,counter);
    	return ::svm_value_boolean_new__raw(svm,c->_counter<c->_limit);
    %}

Et sauvegardez ce fichier.

Pour le moment, la syntaxe de ce fichier n'est pas importante. Elle sera détaillée dans plusieurs didacticiels à venir.

## Génération du code C/C++

Lors de l'installation de la machine virtuelle, un binaire appellé `svm_plugin` est également installé sur le système. C'est ce binaire qui permet de transformer le fichier vu ci-dessus pour le transformer en code C/C++.

Invoquez le générateur d'extension :

    svm_plugin -fi generation.svm_plugin | bash
    Plugin generator for Simple Virtual Machine 2.1.20230101
    Use -h option for help
    Reading plugin definition from file generation.svm_plugin... OK
    Parsing plugin definition... OK
    Generating and parsing plugin configuration string... OK
    Generating plugin files... OK
    Generating plugin creation shell script to stdout... OK
    Generating plugin generation in directory svmplugingeneration

    Generated files:
    AUTHORS
    ChangeLog
    Makefile.am
    Makefile.inc
    Makefile.local
    NEWS
    README
    configure.ac
    doc/Makefile.am
    doc/svm_plugin_generation.man
    plugin_configuration_string
    plugin_install
    src/Makefile.am
    src/plugin.cpp
    src/plugin.h
    test/Makefile.am

    For common installations of this plugin, you can use the provided install script.
    For more details, execute:

    ./svmplugingeneration/plugin_install -h

Notez que la sortie du générateur est redirigée vers bash : en effet, le générateur produit un script shell qui doit être exécuté.

Vous pouvez entrer dans le répertoire contenant le code C/C++ de l'extension et regarder les fichiers générés. Les deux fichiers ayant le plus de contenu propre à l'extension sont :

- doc/svm_plugin_generation.man : ce fichier contient la page de manuel de l'extension;
- src/plugin.cpp : ce fichier contient le code source C/C++ de l'extension :
  - la première fonction générée (plugin_configure) permet à l'extension de se déclarer auprès de la machine virtuelle, de vérifier sa compatibilité avec la machine virtuelle, et fournir la liste des objets définis dans l'extension,
  - ensuite, une liste de macros est définie pour permettre d'accélerer encore l'écriture des extensions,
  - puis, la struct C++ du type generation.counter et les fonctions qui lui sont associées sont présentes,
  - enfin, pour chaque instruction du fichier d'origine, une fonction C++ est générée.

## Compilation et installation

Pour compiler l'extension, vous pouvez utiliser le script d'installation généré :

    ./svmplugingeneration/plugin_install -l
    g++ -std=c++14 -o src/plugin.o -c src/plugin.cpp -fPIC -DPIC  -I.
    g++ -std=c++14 -shared -o libsvmgeneration.so -fPIC -DPIC -Wl,-L/usr/local/lib/svm -lsvmplugininterface -Wl,-soname -Wl,libsvmgeneration.so   src/plugin.o

Le fichier résultat est un .so (le résultat de cette commande peut varier selon les systèmes d'exploitation) :

    file ./svmplugingeneration/libsvmgeneration.so
    svmplugingeneration/libsvmgeneration.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, not stripped

Notez que le générateur d'extension fournit également un canevas minimal pour installer l'extension en utilisant les autotools. Référez vous à la documentation des autotools pour plus d'informations sur ce type d'installation.

# Utilisation d'une extension générée

## Ajout de l'extension

Pour inclure la nouvelle extension, modifiez le code :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin generation exploration
    END
    LOG
    DEBUG "Plugin generation"
    LOCAL PLUGIN "svmplugingeneration/libsvmgeneration.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    	END
    END

Vous pouvez lancez l'application en mode débugueur, et regarder la fenêtre des extensions :

Plugin generation
Plugins

Definitions
TYPE generation.counter
INSTRUCTION generation.check generation.counter -> BLN
INSTRUCTION generation.new INT -> generation.counter
INSTRUCTION generation.touch MUTABLE generation.counter

in
Filter

Vous y trouvez les objets tels que définis dans le fichier d'extension proposé en exemple.

## Modification du code

Modifiez le code pour utiliser l'extension :

    #!/usr/bin/env svm
    DESCRIPTION
    Plugin generation exploration
    END
    LOG
    DEBUG "Plugin generation"
    LOCAL PLUGIN "svmplugingeneration/libsvmgeneration.so"
    PLUGIN "svmcom.so"
    PROCESS "application"
    	CODE "main" INLINE
    		:debug BREAK
    		:memory generation.counter/c, BLN/b
    		:generation.new 3 -> &c
    	:label loop
    		:com.message @&c
    		:generation.touch @&c
    		:generation.check @&c -> &b
    		:goto loop :when @&b TRUE
    		:com.message @&c
    	END
    END

Puis lancez l'application :

    ./generation.svm
    0/3
    1/3
    2/3
    3/3

L'extension présentée ici n'a rien de phénoménal, car elle définit un simple compteur avec une limite qui peut être utilisé comme compteur de boucle, entre autres utilisations.

- Une extension peut s'écrire dans un fichier unique avec l'extension .svm_plugin.
- Le générateur d'extension produit les fichiers sources en C/C++.
- Ces fichiers peuvent être compilés pour construire l'extension utilisable par la machine virtuelle.
- La directive de code `PLUGIN` permet d'inclure les extensions générées à la machine virtuelle en vue de son utilisation dans le code.
- La machine virtuelle peut être vue comme un orchestrateur bas niveau de types et de fonctions C ou C++, comme le shell le fait avec des processus.

# Conclusion

Vous venez de voir comment générer une extension pour la machine virtuelle.

La capacité à pouvoir écrire ses propres extensions permet d'une part de répondre aux exigences de performance des applications : lorsque le langage de la machine s'avère trop lent pour réaliser un calcul, le transcrire en C/C++ permet de l'exécuter beaucoup plus rapidement sans toutefois être contraint de tout exprimer en C/C++.

Cela permet d'autre part de répondre à des besoins spécifiques en termes de stockage ou de comportement, que la machine ne peut pas supporter de part sa généricité.

Enfin, les extensions permettent d'isoler les différents aspects d'une application, de les tester séparément pour une plus grande robustesse d'exécution, et de pouvoir employer rapidement les contributions (libres ou propriétaires) des autres utilisateurs de la Simple Virtual Machine.