Files
Sprinter-SDCC/docs/project-reorganization.md
2026-09-17 22:59:47 +03:00

317 lines
33 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Разделение Sprinter-CC, MAME и приложений
Статус: разделение выполнено, локальные репозитории зафиксированы,
Sprinter-CC опубликован. Открытые проверки перечислены ниже. Дата обновления:
2026-09-16.
## Цель и границы
Тулкит, эмулятор, примеры и реальные приложения должны разрабатываться и
версионироваться независимо. Приложение собирается из собственного клона,
если ему указан только путь к установленному Sprinter-CC. Для запуска в
эмуляторе дополнительно указывается путь к подготовленной среде MAME либо
необходимые отдельные пути. Ни соседний репозиторий Examples, ни исходники
MAME приложению не нужны.
Предлагаемая раскладка на машине разработчика:
```text
~/Projects/DIY/Z80/Sprinter/
├── C-Compiler/ # Sprinter-CC
├── MAME/ # прежний fork MAME 0.287, локальные ресурсы
├── MAME.HT/ # новый fork Holub/Tolik, сборка sprinter
├── Examples/ # один Git-репозиторий примеров
├── Applications/ # каталог без собственного Git
│ ├── SprPoP/ # самостоятельный Git-репозиторий
│ ├── Volkov/ # самостоятельный Git-репозиторий
│ └── PoP-Archive/ # архивный проект, если история нужна отдельно
└── VSCode-Sprinter/ # Git-репозиторий расширения VS Code
```
Имена `C-Compiler`, `Volkov` и `PoP-Archive` приняты для локальной раскладки;
адреса Git remote новых репозиториев будут добавлены после создания доступных
для записи URL.
Отсутствие remote не мешает сохранить независимую локальную историю. Папка
`Applications/` не становится общим репозиторием: каждый продукт имеет свою
историю, релизы, игнорируемые ресурсы и тесты. Физическое расположение рядом
удобно, но не входит в контракт сборки.
Локальные точки истории после разделения:
| Репозиторий | Split/base | Итоговый локальный commit |
|---|---|---|
| Examples | `502d735` | `a76852d` |
| SprPoP | `4507ba9` | `bd300b3` |
| Volkov | `a71e3c5` | `3c1956b` |
| PoP-Archive | `716c639` | `54d0b3d` |
| VSCode-Sprinter | `68a821e` | `abfc29d` (`901d91a` — функциональные изменения) |
| MAME | baseline `b0c4527c`, backend/MCP `fe7ee37a` | `37b89b78` |
| MAME.HT | Holub/Tolik `7f64914880f`, backend `46e89112836`, plugin `1188177a516` | `e0c509c7150` (рецепты и ранний callback), `bb79847affd` (полный raw MCP smoke test и frontend) |
Первые пять base-коммитов получены из подготовительного коммита Sprinter-CC
через `git subtree split`; поэтому их история прослеживается до исходного
монорепозитория. У выделенных репозиториев пока нет настроенных remote.
## Что принадлежит каждому проекту
| Проект | Что остаётся/переходит | Причина |
|---|---|---|
| Sprinter-CC | `bin/`, `runtime/`, `libc/`, `libbgi/`, `lib/`, общие `toolchain/`, `tests/`, `testkit/`, `app.mk`, справочник API, платформенные исследования, `release_docs/`, рецепт SDCC в `third_party/` | Это target SDK, его ABI, инструменты и собственные регрессионные тесты. libc/libbgi пока остаются вместе: их версия и ABI тесно связаны с `sprinter-cc`; дальнейшее выделение возможно после стабильного интерфейса. |
| MAME | Прежний `../MAME` 0.287 и локальные ROM/DSS/CHD, пока новая среда не подготовлена | История проверенной сборки и ресурсы остаются доступными для сравнения и совместимости. |
| MAME.HT | Новый `../MAME.HT` Holub/Tolik: драйвер, OSD, backend `sdbg`, raw `mamebridge`/`mame_mcp.py`, рецепты stock/sdbg с выходом `sprinter` | Это активный исходный fork; его нельзя подменять исходниками MAME 0.287, а патчи и бинарники проверяются на его собственной базе. |
| Examples | Выделенный `../Examples`: `balls`, `mdview`, `mdview2`, `rpgwalk`, `scroll`, `space` и относящиеся к ним ресурсы/документы | Это демонстрации SDK с общей версией. Один репозиторий избегает множества мелких релизов. |
| SprPoP | Всё из прежнего `applications/SprPoP/`: исходники, конверторы, тесты, собственные ресурсы и планы | Уже почти автономное приложение; оригинальные ресурсы и дальше остаются внешними. |
| Volkov | Всё из прежнего `applications/Volkov/`: исходники, сценарии MAME, собственные тестовые носители и документы | Продукт и его проверки должны развиваться без дерева тулкита. |
| PoP-Archive | Прежний `applications/PoP/` как архив PoC/roomtest и исследований | Не смешивать прежнюю историю с активным SprPoP. Архив сохранён самостоятельным рабочим репозиторием. |
| VSCode-Sprinter | Выделенный `../VSCode-Sprinter`: extension, задачи сборки, конфигурации и тесты клиентской части | У расширения свои версии, упаковка VSIX и цикл обновления. Отладочный Python backend остаётся в SDK. |
`applications/DN/DosNavigator` и вложенные чужие клоны в PoP/Volkov —
референсы, не Sprinter-приложения. Их не превращать в продуктовые репозитории
и не коммитить вместе с портами. Локально их можно хранить в `References/`
или получать по воспроизводимой инструкции с указанием upstream и revision.
`docs/sources/`, `docs/extra/` и скачанный SDCC также не являются новым
проектом: это игнорируемые справочные/загруженные материалы. Отдельно
проверить, какие tracked файлы `third_party/16x16-RPG-characters` нужны
`rpgwalk` и старому PoP; каждый потребитель получает собственный ресурс или
явный рецепт его загрузки. Лицензии и происхождение сохранить.
## Контракт сборки и запуска приложения
`SPRINTER_ROOT` указывает на готовый Sprinter-CC. Это единственный внешний
путь, обязательный для сборки `.exe`, host-тестов и собственных генераторов
ресурсов. В `app.mk` убрать вывод MAME из `PROJ_ROOT`; оставить
совместимый alias `PROJ_ROOT := $(SPRINTER_ROOT)` там, где это необходимо на
переходный период. Приложения проверяют, что по пути существуют
`bin/sprinter-cc`, `app.mk` и нужные библиотеки, и сообщают ошибку до начала
сборки. При отсутствии `SPRINTER_ROOT` не угадывать прежнее `../..`: после
переноса такой путь может случайно указывать на чужой каталог.
`MAME_HOME` — необязательный для сборки путь к подготовленной **среде запуска**
MAME, а не к его исходникам. Стандартные пути внутри `MAME_HOME` задают
контракт установленной среды и допускают переопределение из окружения, аргументов `make` или
локального игнорируемого файла настроек. Если `MAME_HOME` не задан,
необходимые пути можно указать отдельно; отсутствие обоих источников
диагностировать в цели запуска, не превращая пустое значение в путь от
корня файловой системы:
```make
MAME_HOME ?=
MAME_BIN ?=
MAME_ROMPATH ?= $(if $(strip $(MAME_HOME)),$(MAME_HOME)/roms,)
MAME_DSS_IMAGE ?= $(if $(strip $(MAME_HOME)),$(MAME_HOME)/IMG/dss171u.img,)
MAME_SYSTEM_HDD_IMAGE ?= $(if $(strip $(MAME_HOME)),$(MAME_HOME)/IMG/sp_hdd_sys.chd,)
MAME_BIOS ?= v3.06
```
`MAME_BIOS` — имя варианта для аргумента `-bios`; ROM-файлы MAME ищет в
`MAME_ROMPATH`. `MAME_SYSTEM_HDD_IMAGE` добавлен потому, что системный CHD
нужен существующим сценариям. Если используется CD, NeoGS или второй
системный носитель, пути к ним сделать отдельными необязательными настройками
профиля запуска; не прибивать их к Makefile каждого приложения. Уточнить по
фактическим сценариям, когда нужен `MAME_DSS_IMAGE`: обычный `run`, тест и
DAP-launch должны брать один источник настройки, даже если конкретный профиль
не монтирует DSS-дискету.
В новом `MAME.HT` команда
`make SUBTARGET=sprinter SOURCES=src/mame/sinclair/sprinter.cpp` создаёт
`sprinter`, не `mame.arm`. SDK при наличии `MAME_HOME/sprinter` выбирает его;
для прежних установок сохраняется `MAME_HOME/mame.arm`. Явный `MAME_BIN`
имеет приоритет и позволяет запускать `MAME.HT/sprinter` со старым каталогом
ROM/DSS без копирования образов. Stock/sdbg сборки находятся отдельно и
выбираются явным `MAME_BIN`. Сборка одного
варианта не перезаписывает другой и не меняет молча активный бинарник.
Для запуска с нетипичной установкой можно переопределить каждый путь, не
копируя ROM/CHD в каталог приложения. Все цели запуска валидируют свои
фактически используемые файлы и выводят проверенный путь в диагностике.
Собственный `.img`/`.chd`, результаты сценариев, снимки, Lua-скрипты и
журнал приложения лежат в его `build/` (или другом локальном выходном
каталоге). MAME получает готовый образ аргументом `-flop1`/`-hard2`. Общие
`IMG/mc.img` и `IMG/test_hdd.chd` больше не являются выходами сборки
приложения. `make hdd` готовит локальный образ; `make run` запускает его
без `mame-link`. Для нескольких сценариев создавать отдельные носители и
state-каталоги, чтобы один запуск не перезаписывал чужие файлы. Одновременная
работа нескольких процессов MAME, особенно с MCP bridge, не проверялась и
не гарантируется; отдельная отложенная задача есть в [TODO.md](TODO.md).
Конфигурация разработчика не содержит абсолютных личных путей в Git.
Для `.img` нужен упаковщик из SDK; для `.chd` нынешний `make_hdd.sh`
дополнительно использует внешние `mtools` и `chdman`. Зафиксировать эти
host-зависимости и проверять их перед упаковкой. `chdman` можно находить
через `PATH` либо переопределяемый `CHDMAN_BIN`; путь к исходникам MAME или
полная установка эмулятора для самой сборки `.exe` не нужны.
Временное состояние MAME (`cfg`, `nvram`, `diff`, `snapshot`, IPC) создаётся
в отдельном каталоге сессии. Обычный запуск, автотест и DAP используют одну
функцию/профиль разрешения путей, но разные режимы жизненного цикла и
разные локальные диски. Не требовать закрывать все чужие процессы MAME по
общему шаблону: предотвращать конфликт только за конкретный изменяемый
носитель/IPC-сеанс. Закрытие MAME не должно терять лог и снимки теста.
Обычный `run_sprinter_mame.py` перед стартом копирует `cfg` и `nvram` из
`MAME_HOME` в каталог сессии, затем включает обе клавиатуры в копии
`sprinter.cfg`, сохраняя остальные настройки. Исходная установка не меняется;
отладчик DAP по-прежнему начинает с чистого изолированного состояния.
## Граница MAME и отладки
В репозитории MAME держать точную базовую ревизию fork, stock сборку и
патченный `sdbg` backend как явную ветку/патч с рецептом сборки. Локальный
checkout уже имеет отдельный `.git` и remote
`https://git.snark13.com/snark13/MAME.git`; переносить его как источник,
не копировать `.git` внутрь нового репозитория тулкита. ROM, DSS, CHD,
скачанные assets, исполняемые файлы и пользовательский state игнорировать.
Инструкция установки создаёт стандартный `MAME_HOME`; она проверяет
наличие/версию файлов, но не распространяет их через Git без отдельной
проверки лицензий и источника.
В Sprinter-CC остаются `--src-debug`, C/asm-карта, debug package,
`toolchain/sdbg*`, Python DAP, launcher и Sprinter-специфичный плагин
`sdbgbridge`. Приложение знает только debug build и свои файлы. Launcher
принимает `MAME_HOME` и все переопределяемые пути из общего профиля;
`-pluginspath`, IPC, ожидание DSS, установка точек и `sdbg` протокол — его
внутренняя работа. Сочетание с родным окном MAME остаётся опцией:
`osx` на macOS, `qt`/`imgui` на Linux по возможностям сборки. Stock MAME
можно выбрать для поддержанного штатного backend; режим `sdbg` требует
соответствующей патченной сборки и должен проверять её до запуска.
Native Windows launch/attach пока не обещать: текущий host transport зависит
от Unix sockets/`fcntl` и не прошёл полный Windows сценарий.
Общий `mamebridge` и `mame_mcp.py` остаются с fork MAME, пока используются
как общие инструменты MAME. Sprinter-специфичному `sdbgbridge` отдельный Git
репозиторий сейчас не нужен: он версионируется с DAP-протоколом в SDK и
загружается через `-pluginspath`. Текущий `toolchain/run-mame-mcp.sh` и
`.codex/config.toml` убрать от предположения `mame/sources/MAME` внутри
тулкита; для общего MCP использовать путь к установленному MCP-серверу
MAME, а для Sprinter C-уровня — DAP/session server SDK. Зафиксировать версию
протокола bridge и совместимость SDK ↔ MAME; несовпадение показывать как
ошибку, а не как зависание отладки.
Репозиторий VSCode-Sprinter содержит только extension и клиентские тесты.
По умолчанию он обнаруживает DAP-инструмент из `SPRINTER_ROOT` либо получает
явную настройку пути; не ищет `toolchain/sdbg_dap.py` в открытом workspace.
Build task выполняет `make SRC_DEBUG=1 SPRINTER_ROOT=...` в каталоге
приложения, F5 передаёт debug package, MAME-профиль и собственные data файлы
адаптеру SDK. Поиск проектов не должен зависеть только от буквального
`include $(PROJ_ROOT)/app.mk`: определить простой стабильный признак проекта
или явный каталог в `launch.json`. Версии VSIX, SDK и поддержанной ревизии
MAME документируются вместе; extension не копирует Python backend.
## Известные связи, которые нужно заменить
| Сейчас | Замена и причина |
|---|---|
| Корневые `Makefile` и `app.mk` собирают examples/MAME и пишут общую floppy/HDD под `mame/v306` | В SDK оставить `make`/`size-check`/собственные тесты; упаковщик принимает выходной путь и MAME-профиль. Примеры собираются в Examples, MAME — в MAME. Удаление корневых целей без замены лишило бы пользователя привычного run: документировать новые команды и при необходимости оставить переходные targets с явной подсказкой. |
| `make host-tests` SDK запускает `applications/SprPoP/tests/host` | Тесты игры вызываются из SprPoP по `SPRINTER_ROOT`; SDK тестирует только SDK. При этом общий `testkit` остаётся SDK. |
| SprPoP `mame-link` меняет `MAME_HOME/IMG/test_hdd.chd` | `make run` передаёт `build/hdd/sprpop.chd` как `-hard2`; состояние установки MAME не меняется. |
| Volkov `hdd-p5-viewer` собирает `examples/mdview2` | Сохранить зафиксированный исходный viewer fixture внутри Volkov с лицензией и исходным revision: сценарий проверяет fullscreen/raw/PgDn/EMM и восстановление Commander после реального EXEC; упрощённая заглушка не покрыла бы эти свойства. Локальный fixture уже добавлен. |
| Volkov `tests/run_mame_hdd.sh` и другие сценарии считают MAME `../../mame/v306` | Принять общие переменные MAME и локальный образ, не менять сценарные Lua-файлы без необходимости. |
| PoP `roomtest`, `bgtest`, `poc` ищут собственные `toolchain/` и `SDLPoP` через корень SDK | Ввести `POP_ROOT`/`APP_ROOT` внутри PoP и локальные пути к референсам; общие SDK-инструменты оставить по `SPRINTER_ROOT`. Не переносить чужие источники и оригинальные игровые данные в Git. |
| Examples Makefiles и `rpgwalk/conv_sprites.py` рассчитаны на `../..` и тулкитский `third_party/` | Подключать SDK по `SPRINTER_ROOT`, resource fixture держать рядом с примером либо получать по зафиксированному рецепту. |
| `toolchain/mame_interactive.py`, `tests/sdbg/run_mame_probe.py`, `sdbg_launcher.py` выводят MAME из `PROJECT_ROOT` | Ввести общий профиль путей, локальные образы и явные аргументы; offline `sdbg-tests` не должен требовать MAME. |
| `toolchain/make_release.sh` включает `examples/` в архив SDK, а README описывает общий диск | Выпускать Examples отдельно либо собирать составной release по зафиксированной версии Examples; сначала определить контракт релиза, затем изменить архив и обе документации. |
| Исследовательские docs и код библиотек ссылаются на `applications/PoP/...` и `mame/sources/...` | Сохранять контекст исследования, но заменять рабочие инструкции и относительные ссылки ссылками на соответствующий репозиторий/revision. Архивные наблюдения не удалять. |
## История Git, внешние ресурсы и совместимость
Перед выделением были инвентаризированы незакоммиченные/неотслеживаемые
файлы в корне и отдельный dirty checkout MAME. Работу DAP, extension,
MCP-плагина, MAME patch и документов сначала сохранили в подготовительном
коммите. Истории `examples/`, `applications/SprPoP/`,
`applications/Volkov/` и PoP выделены через `git subtree split`, после чего
каждый результат импортирован как `main` самостоятельного Git-репозитория.
MAME сохранил свою исходную историю и не получил историю родительского SDK.
Новый `.gitignore` каждого проекта покрывает собственные `.exe`, объекты,
debug packages, носители, снимки, внешние источники и секреты локального
конфига. Не переносить автоматически вложенные сторонние `.git` как gitlinks
или submodules. Для ресурсов, которые не входят в Git, указать источник,
контрольную сумму/revision и способ восстановления; релиз и CI не должны
молча зависеть от файлов конкретной машины. Если приложению нужен SDK с
определённым ABI, фиксировать поддерживаемый релиз/commit SDK в его README
или manifest, не пытаться угадывать его по соседнему каталогу.
Во время перехода обеспечить минимальный период совместимости старой
структуры: сначала добавить переменные и альтернативные пути, проверить
старые вызовы, затем переносить деревья. После миграции убрать fallback на
старые относительные пути и диагностировать устаревшие команды. Это не
должно оставлять два параллельных способа записи в общий носитель.
## Порядок работ и критерии готовности
1. **Выполнено — зафиксировать текущую базу.** Список tracked/untracked файлов,
отдельный Git MAME, лицензии/внешние ресурсы, базовые результаты сборок
и smoke-тестов. Сохранить незавершённую отладочную и прикладную работу.
Критерий: никакой исходник не теряется при выделении истории.
2. **Выполнено — стабилизировать контракт SDK.** В `app.mk` разделить build и run,
реализовать `SPRINTER_ROOT`, `MAME_HOME` и переопределения, упаковку
локального образа с проверкой `mtools`/`chdman`, общий профиль путей
и диагностику отсутствующих файлов. Перевести автотесты/launcher без
переноса дерева.
Критерий: приложение собирается без MAME и запускается с нестандартным
`MAME_BIN`/ROM/DSS/System HDD.
3. **Выполнено локально — подготовить MAME отдельно.** Сохранить fork с точной baseline-revision,
stock/sdbg сборки и проверенным способом подготовки `MAME_HOME`.
Перенести MAME patch/общий MCP к их владельцу, проверить обоих провайдеров.
Критерий: два бинарника существуют одновременно, ROM/CHD и state не
коммитятся, patched DAP launch проверен.
4. **Выполнено — выделить Examples.** Переписать относительные пути и источник RPG
графики, определить формат релиза SDK+Examples. Критерий: каждый пример
собирается из собственного клона Examples при одном `SPRINTER_ROOT`,
локальные диски не затрагивают MAME или соседние проекты.
5. **Выполнено — выделить приложения по одному.** Сначала SprPoP как наиболее близкий
к автономному контракту, затем Volkov с локальным viewer fixture, затем
архив PoP с его референсами. Переписать тесты и run-скрипты, сохраняя
их документы и историю. Критерий: каждый продукт собирается и проходит
доступные host/MAME проверки из изолированного клона без Examples и
других приложений.
6. **Выполнено — выделить extension.** Научить VS Code находить SDK DAP независимо от
workspace, запускать build/run/debug приложения и показывать ошибки
разрешения путей/версий. Проверить VSIX в отдельном workspace SprPoP
или Volkov, а не только в `C-Compiler`. Критерий: F5 строит debug package,
ждёт DSS, доходит до `main`, принимает breakpoint/logpoint и клавиатуру;
опция родного окна MAME работает на macOS. Windows остаётся явно
ограниченной до отдельной реализации host transport.
7. **Выполнено — очистить SDK и документы.** Заменить корневые цели, release-скрипт,
README, `AGENTS.md`, инструкции автотеста/отладки и рабочие ссылки.
Проверить `make`, `make -C libc`, `make -C libbgi`, `make size-check`,
SDK host/sdbg tests и отдельные проекты. Критерий: в SDK нет tracked
приложений/примеров и игнорируемого вложенного MAME; инструкции используют
новые пути, а архивные исследования остаются доступны.
## Проверка реализации на 2026-09-16
Успешно выполнены сборка SDK (`make`), отдельные сборки libc/libbgi,
создание `build/media/toolkit-tests.img`, release-smoke, 36 Python-тестов
source debugger (один platform skip), 12 тестов extension, все Examples,
SprPoP в обычном и `SRC_DEBUG=1` режимах с локальным CHD, 17 host-наборов
SprPoP, Volkov и PoP-Archive PoC. Живые последовательные DAP-прогоны
подтвердили patched `sdbg`, stock MAME с `osx`, клавиатурный ввод,
`SDBG_LOG` в обеих консолях и запуск SprPoP с собственного `hard2` до
`main`.
Extension воспроизводимо упакован через `npm ci && npm run package` и VSIX
версии 0.2.0 установлен в локальный VS Code. Рецепт и `package-lock.json`
хранятся в VSCode-Sprinter. Изолированный профиль VS Code с файлами
установленного VSIX выполнил F5-сценарий SprPoP: задача `make SRC_DEBUG=1
hdd` завершилась, DAP остановился в `src/sprpop.c:264` (`main`). Проверка
шла через API extension host; автоматизировать физическое нажатие F5 через
macOS Accessibility из текущего окружения не удалось.
Эталон `make size-check` разобран и обновлён. Десять тестов, использующих
`open()`, выросли на 9 байт из-за исправления таблицы режимов ESTEX после
предыдущего эталона (ревизия `879f2ba`). `openenv` вырос на 188 байт: те же
9 байт и новый тест записи через `O_RDONLY`. Для `w3bgfx` прежняя запись
5243 байта была несвежей: пересборка в отдельном worktree самой ревизии
`879f2ba` тем же SDCC дала 5257 байт, как и текущая сборка. Других
изменений размеров свежих карт нет. Теперь `size-check` сначала собирает
обязательные SDK-тесты, требует их свежие карты и пропускает устаревшие
артефакты необязательных тестов; `size-baseline` сохраняет их прежние
значения, пока эти тесты не собраны заново.
Несколько одновременных MAME, маршрутизация MCP между ними и Windows
transport остаются явно непроверенными сценариями.
Каждый этап заканчивается проверкой в отдельном репозитории и просмотром Git
diff. Новые Git remote для выделенных репозиториев и публикация их релизов
остаются отдельной задачей. MAME пока не публикуется: существующий `origin`
доступен только для чтения. Sprinter-CC публикуется в своём прежнем remote.