26 January 2024
The design and development of C# to C++ code translator was performed solely by CodePorting. It required many investigations, applying multiple approaches, and tests, differing by memory model and other aspects. In the end, two solutions were chosen. One of them is currently being used for C++ releases of Aspose products.
Now it's time to explain the technologies we use in the code translator. The translator is a console application written in C#, which makes it easy to embed into scripts performing typical sequences like translate-compile-test. There is also a GUI component allowing you to do the same by clicking on the buttons.
Syntax analysis is being performed by the NRefactory library in the outdated generation of the translator and by Roslyn in the new one.
The translator uses several AST tree walkthroughs to collect information and generate output C++ code. For C++ code there is no AST representation created, instead, we handle output code in pure text form.
There are many cases when extra information is required to fine-tune the translator. This information is passed via options and attributes. Options are applied to the whole project. Typically, they are used to specify the class export macro name or C# conditional symbols used when parsing the code. Attributes are applied to the types and entities and provide some specific information for them, e.g.: mark which class members require const
or mutable
qualifiers in the translated code or which entities should be excluded from translation.
C# classes and structures are being converted into C++ classes. Their members and source code – into closest analogs. Generic types and methods are mapped to C++ templates. C# references are translated into smart pointers (shared or weak). Reference classes are defined in the Library. Other internal details of the code translator will be described in a separate article.
So, the project translated from C# to C++ depends on our Library instead of .NET libraries:
To build the code translator Library and the translated projects, we use Cmake. Currently, we support VS 2017 and 2019 (Windows), GCC, and Clang (Linux) compilers.
As already mentioned, most of our .NET implementations are thin adapters over third-party libraries, including:
Both the Translator and Library are covered with many tests. Library tests use the GoogleTest framework. Translator tests are mostly written in NUnit/xUnit and are split into several categories, which ensure that:
We use GitLab as a version control system. For CI, we use Jenkins. Translated products are available as NuGet packages and downloadable archives.
While working on this project, we faced a lot of different problems. Some of them were expected, and others were uncovered on the way:
Object
type, and most library classes don't have RTTI. This makes it impossible to map .NET types to STL ones.yield
).Despite all of that, the code translator project is very interesting from a technical point of view, and its academic complicity forces us to learn something new all the time.
While working on the code translator project, we have succeeded in implementing a system that solves an interesting academic task of code translation. We have organized monthly releases of Aspose libraries for the language they were not supposed to work with.
It is planned to publish more articles about the code translator. The next one will explain the conversion process in detail, including how concrete C# constructions are mapped onto C++ ones. Another one will talk about the memory management model.
We will try our best to reply to the questions asked. If the readers are interested in other aspects of code translator development, we may consider writing more articles on it.