Swig est un outil open source permettant d'interfacer du code C/C++ avec un autre langage. Dans le cas d'Arcane, on wrappe les classes C++ en C# pour qu'elles puissent être utilisée dans tout langage utilisant '.Net'.
Il faut au moins la version 4.0 de swig.
Le wrapping se fait en décrivant dans un fichier avec l'extension .i quels seront les fichiers wrappés et la manière de le faire. En général, une classe C++ aura une classe C# de même nom. Par convention, les méthodes C# commencent pas une majuscule. Pour respecter cela, les méthodes des classes wrappées par Arcane sont converties. Par exemple, la méthode C++ Arcane::ISubDomain::caseMng() deviendra en C# la méthode CaseMng()
.
La classe Arcane::String
est convertie en la classe string
de '.Net'.
`A partir du fichier '.i', swig
va générer un fichier C++
et un ensemble de fichiers C#
. Les premiers doivent être compilés comme un code C++
normal sous forme de bibliothèque dynamique et les seconds comme un projet C#
classique. La communication entre le C++
et le C#
se fait via un mécanisme de .Net
appelé PInvoke (pour Platform Invoke
). Lors de l'exécution, la bibliothèque compilée à partir du C++ doit être accessible. Pour cela, il faut qu'elle soit dans le même répertoire que l'assembly C#
ou alors accessible via les variables d'environnement (LD_LIBRARY_PATH sous Unix ou PATH sous Windows).
L'exemple 'eos/csharp' montre comment effectuer le wrapping et lancer le code C#.
Arcane utilise l'outil swig
pour rendre accessible en C#
les différentes classes.
Ce document décrit comment le développeur peut ajouter ces propres classes pour qu'elles soient accessibles en C#
.
L'outil swig
utilise un fichier d'extension .i
pour décrire les classes à wrapper.
Par exemple, on suppose qu'on a une interface C++ représentant l'interface d'un service de calcul d'une équation d'état et qu'on souhaite pouvoir implémenter ce service en C#
. L'interface est définie dans un fichier IEquationOfState.h
:
L'interface définit deux méthodes initEOS
et applyEOS
qu'on souhaite rendre accessible en C#
.
Pour cela, il faut définir un fichier EOSCSharp.i
contenant le code suivant :
Ce fichier comporte trois parties:
.h
des classes qui seront wrappées par swig
.C++
doit être considérée comme une interface C#
, il faut utiliser la macro ARCANE_DECLARE_INTERFACE
pour le spécifier. Le premier paramètre est le nom du namespace
et le second le nom de la classe. A noter que si on souhaite définir plusieurs interfaces, il faut toutes les déclarer avant de faire d'éventuels include
.ARCANE_SWIG_DEFINE_SERVICE
. Cette macro contient 3 arguments. Les deux premiers sont équivalents à ceux de la macro ARCANE_DECLARE_INTERFACE
. Le dernier contient la signature C#
des méthodes de l'interface wrappée. Elle n'est pas obligatoire en théorie mais permet de s'assurer que l'utilisateur implémente bien les méthodes de l'interface. En effet, via le mécanisme swig
cela n'est pas obligatoirement garanti et si l'utilisateur ne surcharge pas les méthodes cela provoque une erreur lors de l'exécution. Swig va alors généré une exception de type DirectorPureVirtualException
.swig
va générer deux types de fichiers :
C#
.C#
qui contiennent les classes générées par swig
et qui seront celles utilisées par le développeur.Pour que le wrapping fonctionne, il faut donc à la fois compiler les fichiers C++ sous la forme d'une bibliothèque dynamique et les fichiers C#
sous la forme d'une assembly.
.Net
puisse appeler facilement du code natif (C/C++), il faut que ce dernier soit accessible sous la forme d'une bibliothèque dynamique. Il faut obligatoirement compiler le code généré C++ généré par swig sous la forme d'une bibliothèque dynamique. Pour être précis, il est possible de faire cela autrement mais cela nécessite l'écriture de code dépendant du runtime (mono
ou coreclr
) utilisé.Si le développeur utilise cmake
, alors il existe un package qui gère à la fois la génération via swig et créé une cible pour le code C++ correspondant. Si notre fichier .i
s'appelle Wrapper.i
et que la cible est arcane_wrapper
, alors on peut utiliser le code suivant :
Pour le code C#
, il faut utiliser un fichier projet C#
qui sera compilé via la commande dotnet build
ou dotnet publish
.