Введение.
В своей предыдущей статье я упомянул Hebron - утилиту для портирования кода с C на C# или на Rust.
В этой статье хотелось бы подробно расписать - как я с ней работаю.
Написанное можно воспринимать как своего рода мануал на тот случай, если кто-нибудь тоже захочет что-нибудь портануть.
Итак, портирование осуществляется в 4 шага:
Первый шаг: работа Hebron.
Hebron - это обычная Class Library и для работы с ней необходимо написать приложение на .NET.
К примеру, вот так выглядит соответствующее приложение, портирующее StbImageSharp: ссылка на Github.
Непосредственно, обращение к Hebron осуществляется в этой строке:
var result = RoslynCodeConverter.Convert(parameters);
parameters содержат путь к исходному файле, о том с какими #defines его препроцессить, какие функции пропускать при портировании и т.д.
result - объект класса RoslynConversionResult. Он содержит набор Dictionary для каждого типа экспортируемого объекта(перечисления, делегаты, структуры, функции и т.д.): ключом является имя объекта, а значением сгенерированный код на C#.
После обращение к Hebron, приложение пишет код по разным файлам так, что каждому формату картинок соответствует свой файл: код связанный с загрузкой Png пишется в StbImage.Generated.Png.cs, Jpg - в StbImage.Generated.Jpg.cs и т.д.
Однако, к сожалению, сгенерированный код сходу не компилируется из-за синтаксических ошибок. Поэтому требуется второй шаг.
Второй шаг: ручные правки.
Для начала я форматирую в Visual Studio все сгенерированные файлы(Ctrl-A, Ctrl-K, Ctrl-F), чтобы они стали более читаемыми. Затем приступаю к правке синтаксических ошибок.
Это долгий и сложный процесс, где приходится много превозмогать. Поскольку часто попадаются такие ошибки перед которыми хочется просто развести руками.
Часто приходится вносить правки в оригинальный исходный файл: вникать в логику оригинального кода и переписывать её таким образом, чтобы Hebron таки смог переварить изменённый код.
Впрочем, о том какие различия между C и C# вызывают больше всего боли при портировании я планирую запилить отдельную большую статью с примерами кода.
Третий шаг: фикс багов.
Когда новая библиотека начинает компилироваться, то я обычно пишу какое-нибудь простенькое тестовое приложение, чтобы протестировать новый проект.
Если он работает не так, как оригинал, то приходится разбираться в чём заключается проблема. Т.е. запускать две студии: в одной дебажить новую библиотеку, а в другой - оригинал. И дебаггерские шаг за шагом находить расхождения в логике.
Порой на этой требуется не меньше времени и превозмогания, чем на фикс синтаксических ошибок.
К примеру, однажды я потратил много времени на поиск бага в StbVorbisSharp.
Проблема оказалась в файле StbVorbisSharp.Generated.cs, в строке:
int book = g->subclass_books[pclass * 8 + (cval & csub)];
cval & csub не были окружены скобочками. Из-за чего это выражение считалось не так, как надо.
Наконец, когда новая библиотека начинает более ни менее работать, я приступаю к последнему шагу.
Четвёртый шаг: чистка кода.
Здесь нужно сказать, что Hebron не скупится на скобочки(из описания предыдущего шага можно понять почему) или приведения к типам. Из-за чего сгенерированный код вызывает ужас у студии и она предлагает мне сделать множество автоисправлений. Выглядит это примерно так:
Чтобы решить эту проблему, я обычно запускаю Rider и осуществляю Code Cleanup(Ctrl-E, Ctrl-C). Я пользуюсь бесплатной лицензией, которую JetBrains предоставляет для проектов с открытым исходным кодом.
После очистки кода новая библиотека готова.
Кстати, пользуясь случаем, хочу поблагодарить JetBrains как за Rider, так и за лицензию. Спасибо!
Надеюсь, кто-нибудь из официальных представителей на хабре это прочитает.
Прочие порты.
Напоследок я бы хотел рассказать о моих портах, не входящих в StbSharp.
FontStashSharp. На самом деле, этот проект уже нельзя считать портом, поскольку фактически весь оригинальный код был переписан. Неизменным остался, пожалуй, лишь код упаковки прямоугольников на атласе в классе FontAtlas.
NvgSharp. Проект используется в отечественном игровом движке коммерческого уровня под названием Citrus.
DdsKtxSharp. Не слишком известный проект, умеющий загружать картинки в форматах DDS и KTX. Важно отметить, что декодировать он их не умеет. Предполагается, что декодированием будет заниматься видеоускоритель.
SamSharp. Самый неизвестный проект, синтезирующий человеческую речь по какому-то древнему алгоритму, используемому ещё в Commodore C64. Важно отметить, что у оригинального кода не было свободной лицензии, поэтому её нет и у порта.
Пример работы:
Эпилог.
Ну и совсем напоследок скажу, что готов принимать заявки на портирование. Для подачи такой заявки достаточно создать соответствующий кейс в Hebron.
freetype и sqlite можно не предлагать. Поскольку к ним я уже приступал. И сломался на втором шаге. Собственно, вот SqliteSharp. FreeTypeSharp же история не сохранила.
Вот теперь, действительно, всё :)
Комментарии (3)
AlexPoz
11.09.2022 11:20-1Как я портирова питон на шарпы(питон с неадекватным шифрованием): на шарпах (яве пыхе жабаскрипте и плюсах) не удалось повторить алгоритм шифрования, вот такая эта гадюка. А требование было шифровать как у них. Решение: поднимаешь ещё один кубик, собираешь там все какахи и забываешь что там лежит)) Если не говорить о проблеме, то ее как будто бы и нет)
Вообще мне религия не позволяет держать зоопарк и тем более на скриптовых языках, но как известно, мусульманину можно свинину, которая не касалась земли. Так и мне можно скриптик, который не касался змеи)
hbn3
Конкуренты у Hebron есть?
Если да — то не плохо было бы добавить секцию почему решились писать свою реализацию или можно матрицу сравнения фич.
rds1983 Автор
Знаю только о существовании https://github.com/immunant/c2rust