Как я портировал свой (очень) старый пет-проект с Delphi 7 на Zig с помощью LLM
Привет, Хабр! Хочу поделиться историей реинкарнации моего старого пет-проекта — утилиты rulers (экранные линейки, «как в фотошопе»). В 2007 году это был простой инструмент для замеров и выравнивания элементов интерфейса прямо на экране, написанный на Delphi.

Почти два десятилетия спустя я решил воскресить его, но с современным подходом: портировать на zig, да ещё и задействовав LLM для автоматизации. Почему? Потому что я реально фанатею от языка zig, и руки так и чешутся на нём что-то написать. Но переписывать не маленький кусок старого кода — занятие довольно унылое, и я всё откладывал его в «долгий ящик». С другой стороны, я, как реальный ИИ-скептик, с сомнением отношусь к новомодному вайб-кодингу и не доверяю таким инструментам. Но, всё же я решил рискнуть и попробовать, если не для написания нового кода, то хотя-бы для портирования уже написанного. Наверное, шанс на успех тут будет выше. Эта статья о том, что у меня получилось (и не получилось).
Исходный проект: GDI+ под Windows
Исходный код Delphi был компактным (меньше 1000 строк), но использовал нестандартную библиотек для доступа к GDI+ (стандартной тогда в Delphi не было), и я опасался, что LLM не справится с ней.
Но если исключить все технические мелочи, то по сути там было только создание окошек (отдельное для линеек и по одному для каждой направляющей), а GDI+ использовался совсем немного. Интерфейса же не было никакого, все действия производились различной комбинацией шорткатов: для разных действий были использованы все 3 кнопки мыши, в том числе с разными модификаторами.
Целями этого портирования, кроме поиграться с zig-ом, были ещё освежение под x64 платфому, а также желание сделать несколько фиксов: добавить контекстное меню (вместо странных и неочевидных шорткатов, которые на ноутбуке иногда даже нельзя выполнить) и добавить поддержку нескольких мониторов (раньше это было в диковинку, а сейчас — повсеместно).
И очень хотелось сохранить очень малое потребление ресурсов, чтобы не как electron, когда “hello world!” занимает 150 МБ на диске и ещё полгигабайта в памяти. Zig с этим должен прекрасно справиться.
LLM, сконвертируй этот код
Я решил немного умерить свой скептицизм и отдать черновую работу LLM. Я поленился что-то устанавливать на свой компьютер, возиться с докерами и прочей ерундой, поэтому доверился какому-то сайту, который заявляет, что является оболочкой к claude. Залил туда исходника на Delphi, написал “сконвертируй это в zig 0.14” и нажал [Enter]… Внезапно шайтан-машина начала создавать файлы и писать туда код, причём вполне похожий на нормальный.
Конечно, с первой попытки проект не скомпилировался. Zig — язык довольно молодой, да ещё и с регулярно обновляющимися версиями. Так что я посчитал вообще чудом то, что ошибок довольно мало. Я их исправил вручную, код скомпилировался, но не слинковался…
Несколько ошибок были связаны с изменением синтаксиса от zig 0.13 к zig 0.14, но две штуки были связаны с тем, что, транслируя вызовы GDI+, нейросеть сгаллюцинировала пару штук, которые ей хотелось увидеть, но таких функций просто не существует. Благо, нашлись похожие и я быстро поправил это недоразумение.
Кроме удивления, «вау, оно работает!», и некоторого снижения скепсиса, у меня появились подозрения, что нейросеть могла напортачить ещё где-то, при этом код будет выглядеть «идентично натуральному», компилироваться и даже запускаться, но делать что-то не то.
Внезапно, одна фишка zig-а оказалась очень удобной для LLM: освобождение ресурсов во всех примерах и в большинстве опенсорсных проектов происходит в defer сразу же после инициализации ресурса (или выделения памяти), так что нейросеть, натренированная на таких примерах, щедро удобрила код defer-ами везде, где надо, пропустила только один не очень очевидный случай.
Ложка дёгтя
LLM пишет код так, как будто ей платят за строки (или за токены), всё очень многословно, с дебильными комментариями типа:
// increment integer variable n
n += 1;
Так что за волшебным роботом всё-таки предстоит убираться кожаным мешкам. Либо терпеть код ещё хуже «индусского»…
Ещё у нейросети что-то не заладилось с чётностью и в итоге перепутались большие и мелкие засечки на линейках.
мем в тему

Причём заметил я это только через несколько дней:

И ещё один камень, теперь в огород Zig: в версии 0.14 перестал работать следующий код:
exe.subsystem = .Windows;
Теперь всегда создаётся окно консоли, которое мне совершенно не нужно. Пока что я выкрутился тем, что после билда меняю 212-й байт бинарника с 0x03 IMAGE_SUBSYSTEM_WINDOWS_CUI
на 0x02 IMAGE_SUBSYSTEM_WINDOWS_GUI
, но надеюсь скоро это исправят.
Апгрейд кода
Дальше я решил реализовать что-то новое. Например, поддержку нескольких мониторов. Но то-ли я не умею в prompt-engineering, то-ли ллм ещё не готовы писать нативный код на zig, какой-то код сгенерировался, но работал он через одно место и не всегда адекватно, так что в итоге пришлось написать всё самому; хотя буду честен, импорты winapi, которые сгенерировала нейросеть, мне очень пригодились.
LLM, напиши выводы
как будто кто-то их читает
Этот проект стал отличной иллюстрацией того, как можно вдохнуть новую жизнь в старое хобби, совместив ностальгию по старому коду с возможностями новых технологий. LLM отлично подходит как помощник в портировании и первичной генерации кода, особенно когда вы примерно понимаете, что должно получиться. Zig, в свою очередь, продолжает радовать своей минималистичностью и предсказуемостью, хотя и требует внимания к изменениям в синтаксисе между версиями.
Если вы, как и я, долго откладывали обновление старого проекта, потому что лень разбираться с устаревшими подходами — попробуйте дать шанс LLM и какому-нибудь свежему языку. Возможно, вы тоже приятно удивитесь.
Бла-бла-бла...
Исходники (и бинарники) проекта на GitHub.
Итог: портирование заняло один выходной. И ещё полчаса через три дня, когда я заметил баг с чётностью. Использование LLM ускорило портирование, вручную я бы копался в рутине очень долго (и скорее всего даже не начал бы этим заниматься). Но всё же, учитывая неочевидные косяки, что-то ответственное я бы нейросетям не доверил. Возможно, я попробую этот инструмент ещё как-нибудь, но только на пет-проектах.
P.S. Иногда бывает так, что ваш код старше некоторых коллег — как в этому относиться, я пока сам не понял…
evgeniy_kudinov
Картинка с зорким глазом реально передает ощущения, когда работаешь с ллм и ходишь по кругу)