Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Модернизация кодегенератора и системы работы с зависимостями #2912

Open
ForNeVeR opened this issue Jul 30, 2023 · 9 comments

Comments

@ForNeVeR
Copy link
Contributor

ForNeVeR commented Jul 30, 2023

На данный момент перед развитием компилятором стоит ряд принципиальных препятствий, которые мешают использовать его в новых окружениях (в первую очередь .NET Core / .NET 5+).

  1. Компилятор загружает в свой процесс библиотечные сборки, используемые пользовательской программой.

    • Это не даёт нам возможности поддержать multi-targeting или кросс-компиляцию (компилировать сборку для .NET Core, запускаясь на .NET Framework — потому что мы не сможем загрузить зависимости).
    • Это не даёт нам возможности работать с архитектуро-зависимыми сборками для другой архитектуры (например, с x64 сборками на x86 системе, или с ARM64 сборками на x64 системе).
    • Это создаёт путаницу и проблемы при работе с NuGet-библиотеками, применяющими гибкое версионирование: нам приходится писать достаточно сложный код в компиляторе для работы со сборками, и даже после всех ухищрений мы не можем поддержать все сценарии (например, загрузить несколько разных версий одной и той же сборки не получится — а, например, в C# есть даже специальный языковой механизм assembly aliases для работы в случаях, когда это очень хочется сделать — но в PascalABC.NET мы на данный момент даже создать такой механизм, кажется, не сможем, даже если захотим).
  2. Для генерации кода используется System.Reflection.Emit.

    Это очень удобный способ генерации метаданных и байткода, но он обладает существенными ограничениями.

    • Поскольку Reflection.Emit занимается генерацией кода во время исполнения (компилятора), он требует наличия всех библиотек в этом же процессе компилятора. Что влечёт за собой все последствия, описанные в п. 1.
    • Для сохранения сборок используется AssemblyBuilder.Save, который до сих пор не поддерживается в современных версиях .NET (и не будет поддерживаться даже в 8, хотя небольшой и очень медленный прогресс в этом направлении идёт).
    • Некоторые типы невозможно скомпилировать из-за того, что Reflection.Emit требует последовательной их генерации. Я не помню точных примеров (мы их находили, когда писали LENS), но некоторые виды взаимозависимых типов могут доставить неприятности. Что-то вроде такого, кажется, не было возможно сгенерировать:
      class A {
        class NestedA : B.NestedB {}
      }
      
      class B : A {
        class NestedB : A.NestedA {}
      }

Для решения обозначенных проблем предлагаю следующий план действий.

  1. Переписать кодогенерацию вместо Reflection.Emit на Mono.Cecil.

    Это позволит нам разрешить все проблемы из п. 2, и технически разблокирует дорогу для запуска компилятора на .NET 5+. Возможно, он даже без дополнительных изменений запустится (так же, как на Mono).

    Это весьма объёмная и неудобная работа, потому что её нужно делать «за один присест»: не получится частично перевести некоторые возможности на новый движок кодогенерации. Надо переводить сразу всё.

    К счастью, API Mono.Cecil не очень сильно идеологически отличается от Reflection.Emit, так что я ожидаю, что большая часть работы тут будет чисто механической.

    Зато Mono.Cecil умеет работать с библиотеками, загруженными в текущий процесс, и их можно использовать в сгенерированном коде (если правильно импортировать в метаданные, что, как правило, несложно). Поэтому эта работа не становится автоматически заблокированной из-за необходимости также заодно переписывать взаимодействие с библиотечными сборками.

    Основное место выполнения этой работы — кажется, файл NETGenerator.cs, в котором почти 12 тысяч строк.

  2. Переписать работу с библиотеками: полностью отказаться от Assembly.Load*, вместо этого подгружать сборки через Mono.Cecil.

    Это полностью ликвидирует все проблемы, связанные с невозможностью загрузить сборки или перечислить типы в них в рамках текущего процесса: компилятор будет работать только с метаданными сборок, которые обрабатываются простым портабельным кодом.

    Также это позволит очень просто выполнять кросс-компиляцию под другие версии целевого рантайма (то есть можно будет компилироваться под .NET Core, даже ещё не выполняясь на нём).

Хочется услышать мнения разработчиков по этому вопросу.

Со своей стороны могу отметить, что такая организация работы бы приблизила PascalABC.NET к схеме, по которой работают современные компиляторы C# и F# (там, конечно, используется не Cecil, но тоже написаны отдельные кодогенераторы и загрузчики библиотек, которые не полагаются на соответствующие возможности хост-рантайма). Также, она бы позволила мне продолжить работу над PascalABC.NET SDK более эффективно (потому что сейчас я постоянно спотыкаюсь об неправильно прогружающиеся зависимости, пытаюсь это как-то ремонтировать, в процессе ломается что-нибудь другое и т.д.).

@miks1965
Copy link
Contributor

miks1965 commented Jul 30, 2023

А как будет выглядеть графическая оболочка и графические библиотеки под Linux?

Ведь под .NET Core не идет даже графика Windows Forms. Это значит, что наша оболочка под Линуксом ляжет.
Под mono то она хоть как-то идет

@ForNeVeR
Copy link
Contributor Author

А как будет выглядеть графическая оболочка и графические библиотеки под Linux?

Это достаточно далеко от текущего вопроса про «модернизацию кодогенератора и работы с зависимостями», и вопрос достаточно отдалённого будущего, но если вам интересно, могу рассказать своё видение.

Во-первых, первое время оболочка и библиотеки могут не требоваться; достаточно и того, что сам компилятор поддерживает режим работы на современном рантайме. Для моих личных нужд этого было бы достаточно, но, безусловно, я не планирую как-то портить опыт для всех остальных пользователей языка (как минимум в существующих вариантах применения всё останется как есть).

И поэтому выбрасывать всё, что уже написано на .NET Framework, я не предлагаю. Оно точно так же продолжит работать, а у компилятора появятся дополнительные возможности для работы с новыми рантаймами.

Про IDE

Под Linux уже есть примеры IDE, которые работают с .NET. Собственно, PascalABC.NET SDK я разрабатываю в первую очередь с оглядкой на Rider, для которого, возможно (опять же, в достаточно отдалённом будущем) буду делать более развитую поддержку IDE.

Как по мне, так мы могли бы прекрасно достаточно долгое время жить с Windows-only IDE, а пользователи других ОС пусть приспосабливают то, что им нравится. Если сделать всё достаточно аккуратно, то с кодом на PascalABC.NET, который использует современную SDK, можно будет работать и в AvalonStudio, и в MonoDevelop, и в Visual Studio for Mac, например.

Можно было бы рассмотреть возможность понемногу портироваться на кросс-платформенный UI Framework наподобие Avalonia. На нём, например, написана AvalonStudio — базовые нужды для разработки там решаются превосходно.

Про графические библиотеки

Ответ в целом такой же, как и в предыдущем вопросе: кросс-платформенные фреймворки существуют (и уже примерно год как успешно применяются в коммерческих программах — да, таких немного, но они есть), и на них можно аккуратно портировать код, если в этом есть нужда. Я не изучал того, как именно работает графическая библиотека в PascalABC.NET (и есть ли она вообще), но, если что-то нужно доработать, то можно сделать альтернативные пакеты под разные варианты использования языка (грубо говоря — разные backend для Windows Forms, WPF, Avalonia), и с точки зрения программиста всё будет более-менее в порядке.

Про Windows Forms

Ведь под .NET Core не идет даже графика Windows Forms.

Она «не идёт» только на Linux и macOS.

Windows Forms существует и поддерживается на Windows под .NET Core 3 и новее (на мой взгляд, поддерживается даже лучше и живее, чем WPF на .NET Core).

Ну и, опять же, я бы хотел подчеркнуть, что не предлагаю переписывать оболочку в обозримом будущем. Она вполне себе может продолжать существовать в текущем виде, компилироваться под .NET Framework target, и работать только на Mono под Linux.

Под mono то она хоть как-то идет

К слову, кажется, Mono больше не поддерживает Windows Forms на macOS (там были какие-то непонятные проблемы с используемыми биндингами к Cocoa). И вообще, эта реализация сегодня не развивается, и работать может только «как-то», ни о каком особом удобстве пользователей или же разрешении проблем сейчас уже речи не идёт. Практически весь Mono Desktop доживает последние дни, и я не удивлюсь, если в ближайшее время его закроют, и оставят только для Xamarin и WASM.

Если есть задача разработать среду с поддержкой Linux и macOS, нужно смотреть на другие варианты решения. А если такой задачи пока нет, то можно на новые платформы заходить более консервативно, и для начала задаться целью просто не сломать существующие наработки.

@miks1965
Copy link
Contributor

Спасибо за развернутый ответ

Основная проблема - переход российского образования под Линукс.

Постепенно во всех школах будет Линукс, а с 2024 года - на всех станциях ЕГЭ и на компьютерах участников олимпиад по программированию будет только линукс насколько я понимаю.

Недавно всё было наоборот. А дома у школьников был установлен Windows 99.9%, nfr xnj vs b yt gfhbkbcm/

Сейчас проблема встала в полный рост.

Согласен, что моно уже не поддерживается и так себе решение. Мы еле оживили оболочку под моно ценой многочисленных отказов в интерфейсе.

Но тут сказывается отсутствие нашего опыта. Я например не смог собрать AvalonStudio из исходников. В нее если бы получилось - было бы круто. Мог бы поручить кому нибудь из студентов разобраться

@ForNeVeR
Copy link
Contributor Author

Самая популярная проблема при сборке AvalonStudio (сам не один раз натыкался, когда пытался собрать) — в ней используются Git submodules, и поэтому нужно клонировать репозиторий рекурсивно (в README есть инструкция, git clone --recursive).

Убедитесь, пожалуйста, что вы столкнулись не с этой проблемой. Вдруг получится быстро разблокироваться в этом направлении и сдать студентам? :)

@CreateLab
Copy link

@miks1965 При удачных изменениях sdk, и получения понятного api. На первых парах можно будет легко интегрировать его в visual studio code. В таком расскладе можно будет получить простой инструмент доступный всем, а если @ForNeVeR сделает в дальнейшем поддержку райдера будет вообще замечательно.

Да разработать свою ide на движке авалонии это конечно очень интересно, но есть ли столько времени и ресурсов

@miks1965
Copy link
Contributor

miks1965 commented Aug 4, 2023

Насколько я знаю, плагин PascalABC.NET для vs code есть - наша студентка его разрабатывала. Там не всё работает как надо, но жить вполне можно. Она даже на конференции pascalabc.net 2021 про этот плагин рассказывала.

Просто наши возможности рекламы ограничены

@CreateLab
Copy link

@miks1965 я просто хотел подметить выше замечания Дока, о том, что нет смысла зацикливаться на ui фреймворках, если удасться переработать и поставить полноценный sdk, то придоставить ui к нему не будет особой проблемой.
Хотя опять же из интересного, если работа будет успешно завершена, я могу попробовать так же привлечь своих студентов к разработке ide на avalonia ui

@ForNeVeR
Copy link
Contributor Author

ForNeVeR commented Aug 13, 2023

Пока что планирую начать R&D работы в этом направлении в отдельном репозитории, см. описание проекта.

PR будет оформлен по мере продвижения (что может занять несколько месяцев или больше).

@ghost
Copy link

ghost commented Oct 10, 2023

If you want a cross platform GUI framework, please consider https://github.com/picoe/Eto, too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants