26 janvier 2024
La conception et le développement du traducteur de code C# vers C++ ont été réalisés exclusivement par CodePorting. Cela a nécessité de nombreuses recherches, l'application de plusieurs approches et des tests différents, en fonction du modèle de mémoire et d'autres aspects. Au final, deux solutions ont été choisies. L'une d'entre elles est actuellement utilisée pour les versions C++ des produits Aspose.
Il est maintenant temps d'expliquer les technologies que nous utilisons dans le traducteur de code. Le traducteur est une application console écrite en C#, ce qui facilite son intégration dans des scripts effectuant des séquences typiques telles que traduire-compiler-test. Il existe également un composant GUI vous permettant de faire la même chose en cliquant sur les boutons.
L'analyse syntaxique est effectuée par la bibliothèque NRefactory dans la génération obsolète du traducteur et par Roslyn dans la nouvelle version.
Le traducteur utilise plusieurs parcours d'arbres AST pour collecter des informations et générer du code C++ en sortie. Pour le code C++, il n'y a pas de représentation AST créée, à la place, nous gérons le code de sortie sous forme de texte brut.
Il existe de nombreux cas où des informations supplémentaires sont nécessaires pour affiner le traducteur. Ces informations sont transmises via des options et des attributs. Les options s'appliquent à l'ensemble du projet. Elles sont généralement utilisées pour spécifier le nom du macro d'exportation de classe ou les symboles conditionnels C# utilisés lors de l'analyse du code. Les attributs s'appliquent aux types et aux entités et fournissent des informations spécifiques pour celles-ci, par exemple : indiquer quels membres de classe nécessitent des qualificateurs const
ou mutable
dans le code traduit, ou quelles entités doivent être exclues de la traduction.
Les classes et structures C# sont converties en classes C++. Leurs membres et leur code source sont convertis en analogues les plus proches. Les types et méthodes génériques C# sont mappés sur des modèles C++. Les références C# sont traduites en pointeurs intelligents (partagés ou faibles). Les classes de référence sont définies dans la bibliothèque. D'autres détails internes du traducteur de code seront décrits dans un article séparé.
Ainsi, le projet traduit de C# vers C++ dépend de notre bibliothèque au lieu des bibliothèques .NET :
Pour construire la bibliothèque du traducteur de code et les projets traduits, nous utilisons Cmake. Actuellement, nous prenons en charge les compilateurs VS 2017 et 2019 (Windows), GCC et Clang (Linux).
Comme mentionné précédemment, la plupart de nos implémentations .NET sont de minces adaptateurs sur des bibliothèques tierces, notamment :
Le traducteur et la bibliothèque sont tous deux couverts par de nombreux tests. Les tests de la bibliothèque utilisent le framework GoogleTest. Les tests du traducteur sont principalement écrits avec NUnit/xUnit et sont répartis dans plusieurs catégories, ce qui garantit que :
Nous utilisons GitLab comme système de contrôle de version. Pour l'intégration continue, nous utilisons Jenkins. Les produits traduits sont disponibles sous forme de packages NuGet et d'archives téléchargeables.
Lors de la réalisation de ce projet, nous avons rencontré de nombreux problèmes différents. Certains étaient attendus, tandis que d’autres ont été découverts en cours de route :
Object
, et la plupart des classes de bibliothèque ne disposent pas de RTTI (Run-Time Type Information). Cela rend impossible la mise en correspondance des types .NET avec ceux de la STL (Standard Template Library) en C++.yield
).Malgré tout cela, le projet de traducteur de code est très intéressant d'un point de vue technique, et sa complexité académique nous oblige à apprendre constamment de nouvelles choses.
En travaillant sur le projet de traducteur de code, nous avons réussi à mettre en place un système qui résout une tâche académique intéressante de traduction de code. Nous avons organisé des versions mensuelles des bibliothèques Aspose pour le langage avec lequel elles n'étaient pas censées fonctionner.
Il est prévu de publier plus d'articles sur le traducteur de code. Le prochain article expliquera en détail le processus de conversion, y compris comment les constructions concrètes en C# sont mappées sur celles en C++. Un autre article abordera le modèle de gestion de la mémoire.
Nous ferons de notre mieux pour répondre aux questions posées. Si les lecteurs sont intéressés par d'autres aspects du développement du traducteur de code, nous pourrions envisager d'écrire plus d'articles à ce sujet.