From d25f28e1cdc1388799e6184dcd1fba7cba036187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0=D0=BD=D0=B4=D1=80=20?= =?UTF-8?q?=D0=9F=D0=B5=D1=82=D1=80=D0=BE=D0=B2?= Date: Wed, 16 Sep 2026 15:00:12 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D1=80=D0=BE=D0=B2=D0=B5=D1=80=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20VSIX=20=D0=BF=D0=BE=D1=81=D0=BB=D0=B5=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B8?= =?UTF-8?q?=20=D0=BF=D1=80=D0=B8=D0=BD=D1=8F=D1=82=D1=8C=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B7=D0=BC=D0=B5=D1=80=D0=BD=D1=8B=D0=B9=20=D1=8D=D1=82=D0=B0?= =?UTF-8?q?=D0=BB=D0=BE=D0=BD=20SDK?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Makefile | 8 +-- docs/project-reorganization.md | 30 ++++++++---- docs/size_baseline.tsv | 26 +++++----- toolchain/size_check.py | 89 ++++++++++++++++++++++++++-------- 4 files changed, 105 insertions(+), 48 deletions(-) diff --git a/Makefile b/Makefile index f276792..8fb36b6 100644 --- a/Makefile +++ b/Makefile @@ -86,12 +86,12 @@ sdbg-tests: tools lib $(PYTHON) -m unittest discover -s tests/sdbg -v # Размерный регресс: сверить _CODE всех программ с docs/size_baseline.tsv. -size-check: - $(PYTHON) toolchain/size_check.py +size-check: tests + $(PYTHON) toolchain/size_check.py --require $(TESTS) # Принять текущие размеры как эталон (после осознанных изменений). -size-baseline: - $(PYTHON) toolchain/size_check.py --update +size-baseline: tests + $(PYTHON) toolchain/size_check.py --update --require $(TESTS) clean: $(MAKE) -C toolchain/mkexe clean diff --git a/docs/project-reorganization.md b/docs/project-reorganization.md index 5e88135..da54904 100644 --- a/docs/project-reorganization.md +++ b/docs/project-reorganization.md @@ -249,14 +249,14 @@ debug packages, носители, снимки, внешние источник их документы и историю. Критерий: каждый продукт собирается и проходит доступные host/MAME проверки из изолированного клона без Examples и других приложений. -6. **Реализовано; остаётся ручная проверка установленного VSIX после разделения — выделить extension.** Научить VS Code находить SDK DAP независимо от +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. **Выполнено с открытым размерным baseline — очистить SDK и документы.** Заменить корневые цели, release-скрипт, +7. **Выполнено — очистить SDK и документы.** Заменить корневые цели, release-скрипт, README, `AGENTS.md`, инструкции автотеста/отладки и рабочие ссылки. Проверить `make`, `make -C libc`, `make -C libbgi`, `make size-check`, SDK host/sdbg tests и отдельные проекты. Критерий: в SDK нет tracked @@ -276,15 +276,25 @@ SprPoP, Volkov и PoP-Archive PoC. Живые последовательные D Extension воспроизводимо упакован через `npm ci && npm run package` и VSIX версии 0.2.0 установлен в локальный VS Code. Рецепт и `package-lock.json` -хранятся в VSCode-Sprinter. +хранятся в 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` пока не принят: текущий baseline показывает 12 старых -увеличений (обычно +9 байт, `openenv` +188) и несколько исчезнувших прежних -тестов. Реорганизация не меняла libc/libbgi, поэтому эталон автоматически не -перезаписывался; расхождения нужно разобрать отдельно. После разделения ещё -нужен ручной F5-прогон установленного VSIX в чистом workspace. Несколько -одновременных MAME, маршрутизация MCP между ними и Windows transport остаются -явно непроверенными сценариями. +Эталон `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 для выделенных репозиториев и публикация их релизов diff --git a/docs/size_baseline.tsv b/docs/size_baseline.tsv index 2841e26..6379440 100644 --- a/docs/size_baseline.tsv +++ b/docs/size_baseline.tsv @@ -1,4 +1,4 @@ -# Эталон размеров _CODE (байт); обновление: python3 toolchain/size_check.py --update +# Эталон размеров _CODE (байт); обновление: make size-baseline accfill 3797 accop 7067 argv 3445 @@ -14,18 +14,18 @@ bgitest 3762 bios_text 4475 blitperf 5860 blitw 4939 -cat 927 -cblstream 5944 +cat 936 +cblstream 5953 cbltest 6090 -cblwav 6183 +cblwav 6192 conio 4619 conio2 3943 convbench 3508 dec_test 874 -errno 5980 -fbench 8149 -fdmax 6087 -filetest 10611 +errno 5989 +fbench 8158 +fdmax 6096 +filetest 10620 fpsdiv 4870 gets 523 gfx_dbuf 5207 @@ -40,26 +40,26 @@ ls 4849 malloc 4475 mem_test 4569 mouse 4396 -openenv 6138 +openenv 6326 pageflip 6334 palfile 5406 ptime 5758 rt_test 5216 scroll 6744 -seek 4202 +seek 4211 simple 969 -solidt 11595 +solidt 11604 spranim 9431 spriteclip 4119 sprites 6791 -stattest 7563 +stattest 7572 stdlib 6657 stest2 3658 strtest 1354 text_palette 5038 timedir 5468 w0page 8831 -w3bgfx 5243 +w3bgfx 5257 w3big 3673 w3huge 3700 w3probe 3556 diff --git a/toolchain/size_check.py b/toolchain/size_check.py index ca59336..7c41fc2 100644 --- a/toolchain/size_check.py +++ b/toolchain/size_check.py @@ -4,14 +4,18 @@ size_check.py — размерный регресс-тест: сравнение docs/size_baseline.tsv. Использование: - python3 toolchain/size_check.py # сверка с эталоном - python3 toolchain/size_check.py --update # перезаписать эталон + make size-check # собрать обязательные тесты и сверить с эталоном + make size-baseline # принять свежие размеры, сохранив необязательные -Логика: собираем _CODE из .map каждой программы под tests/, сравниваем с -эталоном. Любое отличие печатается; выход 1 — если есть РОСТ (случайное +Логика: собираем _CODE из свежей .map каждой программы под tests/, сравниваем с +эталоном. Карты, оставшиеся от другой цели или более старые, чем входы +сборки, пропускаются. Любое отличие печатается; выход 1 — если есть РОСТ (случайное разжирение libc), 0 — если только уменьшения/без изменений. Новые программы (нет в эталоне) — предупреждение, добавить через --update. -Запускать после `make all`. +--update заменяет размеры собранных тестов, сохраняя эталоны необязательных +тестов, которые сейчас не собирались. +Прямой запуск скрипта рассчитан на уже собранные тесты; Make-цели сами +собирают обязательный набор и передают его через --require. ТОЛЬКО tests/, без отдельного репозитория Examples: регресс ловит разжирение libc, а для этого хватает мелких тестов — каждый тянет свой кусок библиотеки и пересобирается @@ -20,18 +24,20 @@ docs/size_baseline.tsv. `make all` они убраны (см. корневой Makefile). """ +import argparse import glob import os +from pathlib import Path import re -import sys ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASELINE = os.path.join(ROOT, "docs", "size_baseline.tsv") def collect(): - """Имя программы → размер _CODE (байт) по свежим .map.""" + """Имя программы → размер _CODE (байт) по свежим .map своей цели.""" sizes = {} + skipped = set() pats = [ os.path.join(ROOT, "tests", "*", ".sprinter-cc-*", "*.map"), ] @@ -41,13 +47,43 @@ def collect(): # .map должен лежать в своей папке .sprinter-cc- if os.path.basename(os.path.dirname(map_path)) != ".sprinter-cc-" + name: continue + project = Path(map_path).parents[1] + makefile = project / "Makefile" + if not makefile.is_file(): + continue + declared = re.search(r"^EXAMPLE\s*[:?+]?=\s*(\S+)", + makefile.read_text(), re.M) + if not declared or declared.group(1) != name: + # Например, старый .sprinter-cc-w3bankgfx рядом с w3bgfx. + continue + flags = makefile.read_text() + safe = "--safe" in flags + gfx = "--gfx" in flags + variant = "_safe" if safe else "" + # app.mk сам по себе не является входом линкера: его изменения + # учитываются сборкой через sdbg-config и CC_FLAGS. Проверяем + # только реальные входы, иначе правка run-цели объявит все карты + # устаревшими, хотя размер программы не менялся. + dependencies = [makefile, Path(ROOT) / "bin/sprinter-cc", + Path(ROOT) / "toolchain/mkexe/mkexe", + Path(ROOT) / f"lib/sprinter{variant}.lib"] + if gfx: + dependencies.append(Path(ROOT) / f"lib/bgi256{variant}.lib") + dependencies.extend(project.glob("*.c")) + dependencies.extend(project.glob("*.h")) + dependencies.extend((Path(ROOT) / "runtime").glob("*.s")) + if any(not path.is_file() or + os.path.getmtime(map_path) + 1 < path.stat().st_mtime + for path in dependencies): + skipped.add(name) + continue with open(map_path, encoding="utf-8", errors="replace") as f: for line in f: m = re.match(r"^_CODE\s+([0-9A-Fa-f]+)\s+([0-9A-Fa-f]+)", line) if m: sizes[name] = int(m.group(2), 16) break - return sizes + return sizes, skipped def load_baseline(): @@ -64,23 +100,33 @@ def load_baseline(): def save_baseline(sizes): + accepted = load_baseline() + accepted.update(sizes) with open(BASELINE, "w") as f: f.write("# Эталон размеров _CODE (байт); обновление: " - "python3 toolchain/size_check.py --update\n") - for name in sorted(sizes): - f.write(f"{name}\t{sizes[name]}\n") + "make size-baseline\n") + for name in sorted(accepted): + f.write(f"{name}\t{accepted[name]}\n") def main(): - update = "--update" in sys.argv - sizes = collect() + parser = argparse.ArgumentParser(description="Проверка размера _CODE SDK-тестов") + parser.add_argument("--update", action="store_true") + parser.add_argument("--require", nargs="*", default=[], metavar="TEST") + args = parser.parse_args() + sizes, skipped = collect() + missing = set(args.require) - sizes.keys() + if missing: + print("size_check: нет свежей карты для обязательных тестов: " + + ", ".join(sorted(missing))) + return 2 if not sizes: - print("size_check: .map не найдены — сначала `make all`") + print("size_check: свежие .map не найдены — сначала `make all`") return 2 - if update: + if args.update: save_baseline(sizes) - print(f"size_check: эталон обновлён ({len(sizes)} программ) → " + print(f"size_check: эталон обновлён ({len(sizes)} свежих программ) → " f"{os.path.relpath(BASELINE, ROOT)}") return 0 @@ -90,17 +136,18 @@ def main(): return 2 grew = 0 - for name in sorted(set(sizes) | set(base)): + for name in sorted(sizes): new, old = sizes.get(name), base.get(name) - if new is None: - print(f" {name}: исчез из сборки (был {old} Б)") - elif old is None: + if old is None: print(f" {name}: НОВЫЙ ({new} Б) — добавить в эталон (--update)") elif new != old: mark = "РОСТ" if new > old else "ок, меньше" print(f" {name}: {old} -> {new} ({new - old:+d} Б) [{mark}]") if new > old: grew += 1 + if skipped: + print(f"size_check: {len(skipped)} устаревших карт пропущено: " + + ", ".join(sorted(skipped))) if grew: print(f"size_check: {grew} программ(ы) ВЫРОСЛИ — проверить правки libc") return 1 @@ -109,4 +156,4 @@ def main(): if __name__ == "__main__": - sys.exit(main()) + raise SystemExit(main())