Mazdaywik / refal-5-framework

Фреймворк для трансформации программ на Рефале-5
https://mazdaywik.github.io/refal-5-framework
MIT License
3 stars 0 forks source link

Менеджер пакетов и система сборки для Рефала #10

Open Mazdaywik opened 2 years ago

Mazdaywik commented 2 years ago

Мотивация

У других языков программирования есть свои пакетные менеджеры, а у Рефала нет. И мне обидно.

Кроме того, у меня есть несколько своих проектов на Рефале:

Пишутся и другие проекты на Рефале-5:

К каждому из них скрипт сборки и скрипт запуска пишутся индивидуально.

Между двумя моими проектами есть зависимость: Рефал-05 зависит от фреймворка. Также не исключена зависимость между фреймворком и Рефалом-5λ — не хочется синхронно поддерживать две библиотеки LibraryEx.

Декомпилятор на выходе самостоятельно формирует .rsl-ки, но он выиграл бы, если бы для их формирования он использовал фреймворк (правда, он требует доделки для вставки комментариев в код).

Рефал-5λ содержит копию исходника декомпилятора, она подключена через хитрое слияние ветвей. Тоже было бы неплохо, если бы декомпилятор подключался бы как зависимость.

MSCP-A зависит от библиотеки prefal и для корректной работы вынужден её включать себе в репозиторий. prefal доступен в интернете для загрузки:

http://www.botik.ru/pub/local/scp/refal5/bin/prefal_180216.zip

Запуск программ на Рефале-5 не очень удобен: в командной строке refgo нужно явно перечислять все имена скомпилированных модулей, например так:

https://github.com/TonitaN/MSCP-A/blob/bf4a5175549ff913c52a68f5270a3370d3bf9daa/mscpdo.bat#L1-L7

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

Про зависимости

В Рефале-5λ имеется утилита rlmake, которая умеет находить зависимые файлы в специальным образом размеченных исходниках. Она принимает в командной строке имя единственного файла, находит все файлы, связанные с ним и вызывает компилятор rlc для сборки всех этих файлов.

Разметка осуществляется комментариями

*$FROM ‹имя-файла›

В ‹имени-файла› расширение .ref писать не обязательно. Файлы ищутся в т.н. путях поиска, которые явно указываются в командной строке rlmake, опция --ref5rsl позволяет добавить к путям поиска также и содержимое переменной среды REF5RSL.

Имя метки *$FROM предполагает, что после этого комментария располагается список *$EXTERN, содержащий имена функций, импортируемых из искомого модуля:

*$FROM LibraryEx
$EXTERN ArgList, LoadFile, SaveFile, Map;

Исторически комментарии *$FROM я использовал при раскрутке Модульного Рефала в 2007 году:

С тех пор я уже привык использовать подобного рода комментарии, не только для утилиты rlmake, но и вообще.

Другие программисты тоже используют подобные комментарии перед списками $EXTERN. Пример из MSCP-A:

https://github.com/TonitaN/MSCP-A/blob/bf4a5175549ff913c52a68f5270a3370d3bf9daa/Drive.ref#L69-L88

Пример из SCP4 (версия scp4_000925, файл access.ref):

* basic.ref:
$EXTRN SubsAs, Subs;

* drive.ref:
$EXTRN Dn0;

* trace.ref:
$EXTRN CurrFile, FOutput, Trace, Trace0, CommTrace;

* key.ref:
$EXTRN OutDir, InpDir;
$EXTRN Length, Depth, CallDepth, Simplify, Transient, PutInHistory, Strategy, GoAhead;

Черновик спецификации

Источник вдохновения

Источником вдохновения послужили пакетные менеджеры и системы сборки языков Go и Rust:

У языка Go была позаимствована децентрализованность, у Rust — выделение библиотечного крейта.

Зависимости

Предполагается, что на машине пользователя доступны команды git, wget или curl и какой-то разархиватор zip-файлов (unzip на unix-подобных, для Windows разархиватор указывает пользователь в настройках), а также имеется какая-нибудь реализация Рефала-5 (сам Рефал-5, Рефал-5λ, Рефал-05 с компилятором Си).

Структура проекта

Проект представляет собой папку, в которой имеются следующие файлы и каталоги:

Файл конфигурации r5pm.prj

Файл имеет следующий формат:

[common]
; Компилятор: одно из refc, crefal, refal-5-lambda (или lambda), refal-05
compiler = refc
; Флаги для refgo
refgo_flags = -l1000 -c200

; целевые файлы, имеют вид:
;     имя_в_папке_bin = имя_в_папке_src
[targets]
virus = virus.ref
trojan = my_cool_trojan.ref
backdoor = backdoor.ref

; для целей глобальные настройки можно переопределять
[targets.virus]
refgo_flags = -l2000 -c300

[targets.trojan]
compiler = lambda
lambda_flags = -ODPRS

; зависимости, имеют вид
;     имя_зависимости = путь_для_скачивания
; имя_зависимости нужно для указания дополнительных опций,
; кроме того, имя папки в папке modules/ будет основываться
; на имени зависимости (возможно, в конец припишется число).
[dependencies]
; если путь заканчивается на .zip — это архив,
pr = http://www.botik.ru/pub/local/scp/refal5/bin/prefal_180216.zip
; иначе — репозиторий git, после @ — номер версии (тег)
fw = https://github.com/Mazdaywik/refal-5-framework@1.0

; для зависимостей можно указывать дополнительные опции
[dependencies.pr]
; если распаковать архив prefal_180216.zip, то мы увидим,
; что rsl’ка лежит не в корне архива, а в подпапке prefal
subdir = prefal

Рабочий процесс

Доступны следующие команды:

Если при скачивании зависимостей в скачанном репозитории/архиве в корне нашёлся файл r5pm.prj, извлекаются зависимости из него и скачиваются тоже и далее рекурсивно.

Процесс сборки:

Запускаемый модуль для компиляторов Рефал-05 и Рефал-5λ — исполнимый файл (хотя для Рефала-5λ может быть, например, .dll или .so в зависимости от lambda_flags), тут всё просто.

Запускаемый модуль для Рефала-5 — это пара из скрипта ОС (.bat-файл на Windows ‹имя-цели›.cmd и shell-скрипт для unix-подобных ОС ‹имя-цели› без расширения и с флагом исполнимости) и папки с rsl-ками ‹имя-цели›.rsls. Предполагается, что пользователь эти файл и папку будет копировать, перемещать и переименовывать синхронно. В папке ‹имя-цели›.rsls .rsl-ки будут лежать, переименованными в a.rsl, b.rsl, …, z.rsl, a1.rsl… Возможный вид скриптов запуска (не уверен на счёт экранирования скобок в Bash):

@refgo "%~dpn0%.rsls(a+b+c+d)" -l2000 -c300 %*
#!/bin/sh
refgo "${0}.rsls\(a+b+c+d\)" -l2000 -c300 "$@"

Параметры -l2000 -c300 берутся из refgo_flags в файле конфигурации.

В проекте может отсутствовать папка src/, в этом случае проект может быть использован только как зависимость, ничего в папке bin/ не создаётся. В проекте может отсутствовать папка lib/, в этом случае проект использовать как зависимость бессмысленно.

Плагины

Предполагается, что поддержка отдельных компиляторов (значения опции compiler: refc, crefal, refal-05, refal-5-lambda) будет оформлена как плагины, т.е. не захардкожена напрямую в сам пакетный менеджер.

Плагин будет представлять собой команду r5pm-plugin-compiler-‹имя› вроде r5pm-plugin-compiler-refal-05. Пакетный менеджер будет вызывать соответствующую команду функцией System, передавая ей необходимые опции — интерфейс взаимодействия нам пока не важен. Будут отдельные команды для запроса свойств (вроде расширений импортируемых файлов) и запуска сборки (передаётся файл, где перечислены исходные файлы + всякие опции).

Предустановленными будут плагины для refc и crefal, плагины для Рефала-05 и Рефала-5λ будут устанавливаться вместе с соответствующими компиляторами.

Судьба rlmake

В перспективе этот сборщик должен заменить собой утилиту rlmake, последняя скукожится до плагина.


@TonitaN, вопросы, предложения, замечания, комментарии?

TonitaN commented 2 years ago

Идею всецело поддерживаю. Насчёт деталей реализации - пока не приходит в голову, чего не хватает, кроме одного. Если я собираю проект сразу двумя компиляторами (например, refc и лямбдой - я так делала с MSCP-A; или crefal-ом и refc), то как будет выглядеть результат?

Mazdaywik commented 2 years ago

Об этом я не подумал, спасибо.

Возможный вариант — переопределять опции в командной строке:

r5pm build +common.compiler=lambda
r5pm build +targets.trojan.compiler=refal-05

Надо ещё подумать — делать пакетный менеджер в этом репозитории или создать новый. GitHub позволяет перемещать заявки между репозиториями:

image

Я уже пробовал эту функцию, работает. Попробуй перейти по ссылке https://github.com/Mazdaywik/Refal-05/issues/27.

TonitaN commented 2 years ago

А конфликтов не будет, в случае если используется crefal и refc? Т.е. не появятся ли в одной директории перекрывающие друг друга rsl-файлы?

Mazdaywik commented 2 years ago

В самой первой версии инкрементной сборки не будет, всё будет пересобираться каждый раз заново. А в случае инкрементной сборки нужно будет обеспечить раздельное хранение промежуточных файлов (.rsl,.rasl, .cpp) не только для разных компиляторов, но и для одного компилятора с разными флагами оптимизации.

А по поводу папки ‹имя-цели›.rsls — я предполагаю, что она при каждой пересборке будет создаваться заново. А значит, последующая сборка с другим компилятором перетрёт предыдущую. Точно также, если попеременно собирать одну цель Рефалом-05 и Рефалом-5λ, ‹имя-цели›.exe будет перезаписываться.

Если нужно обеспечить одновременную сборку разными компиляторами (например, для сравнения производительности), то можно сделать несколько целей:

[targets]
my-prog-refc = my-prog.ref
my-prog-crefal  = my-prog.ref
my-prog-lambda = my-prog.ref
my-prog-lambda-opt = my-prog.ref

[targets.my-prog-refc]
compiler = refc

[targets.my-prog-crefal]
compiler = crefal

[targets.my-prog-lambda]
compiler = lambda

[targets.my-prog-lambda-opt]
compiler = lambda
lambda_flags = -ODPRS
Mazdaywik commented 2 years ago

Кстати, имя файла в папке bin/ может не совпадать с именем слева от = в секции [targets]:

[targets]
abcd = defg.ref

[targets.abcd]
name = my-cool-program.v1.exe