Sprinter: добавить отладку C-исходников и интеграцию VS Code

This commit is contained in:
2026-09-15 17:58:41 +03:00
parent 50c6e56b7b
commit e4695b8281
62 changed files with 7147 additions and 27 deletions
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""Живой DAP-проход: C-макрос → breakpoint → обе console без DSS-вывода."""
from __future__ import annotations
import json
import os
from pathlib import Path
import subprocess
import sys
import tempfile
import time
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(Path(__file__).resolve().parent))
sys.path.insert(0, str(ROOT/'toolchain'))
from run_vscode_dap_probe import receive, send, wait_response
from sdbg.server import rpc_call
def main():
provider = 'osx' if '--osx' in sys.argv else 'sdbg'
source = ROOT/'tests/sdbg/fixtures/logmacro.c'
with tempfile.TemporaryDirectory(prefix='sprinter-macro-live-') as temp:
exe = Path(temp)/'logmacro.exe'
build = subprocess.run([str(ROOT/'bin/sprinter-cc'), '-o', str(exe),
'--src-debug', str(source)], cwd=ROOT,
env=dict(os.environ, SPRINTER_PYTHON=sys.executable),
capture_output=True, text=True)
if build.returncode:
raise RuntimeError('Не собрано приложение с SDBG_LOG: '+build.stdout+build.stderr)
process = subprocess.Popen([sys.executable, str(ROOT/'toolchain/sdbg_dap.py')], cwd=ROOT,
stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
buffer = b''
try:
send(process, 1, 'initialize')
_, buffer, _ = wait_response(process, buffer, 'initialize', 10)
send(process, 2, 'launch', {'build': str(exe.with_name('.sprinter-cc-logmacro')),
'debugger': provider, 'dssTimeout': 30})
launched, buffer, events = wait_response(process, buffer, 'launch', 80)
if not any(event.get('event') == 'initialized' for event in events):
event, buffer = receive(process, buffer, 5)
if event.get('event') != 'initialized':
raise RuntimeError('Нет DAP initialized: '+str(event))
send(process, 3, 'configurationDone')
_, buffer, _ = wait_response(process, buffer, 'configurationDone', 10)
send(process, 4, 'stackTrace')
frames, buffer, _ = wait_response(process, buffer, 'stackTrace', 10)
if not frames['body']['stackFrames'][0]['name'].startswith('main'):
raise RuntimeError('Перед стартом нет main: '+str(frames['body']['stackFrames']))
send(process, 5, 'continue')
_, buffer, events = wait_response(process, buffer, 'continue', 10)
outputs = [event for event in events if event.get('event') == 'output']
deadline = time.monotonic()+25
while not any('total=1\n' == event.get('body', {}).get('output') for event in outputs):
if time.monotonic() >= deadline:
raise RuntimeError('SDBG_LOG не пришёл в DAP Debug Console: '+str(outputs[-4:]))
event, buffer = receive(process, buffer, deadline-time.monotonic())
if event.get('event') == 'terminated':
raise RuntimeError('DAP завершился до авторского лога')
if event.get('event') == 'output': outputs.append(event)
socket = launched['body']['socket']
tail = rpc_call(socket, 'mame_console_tail', {'count': 50}, timeout=6)
if not any('total=1' in line for line in tail['lines']):
raise RuntimeError('В debugger console MAME нет total=1: '+str(tail))
print(json.dumps({'event': 'macro_dual_console_verified',
'provider': provider, 'dap_output': 'total=1',
'mame_console': [line for line in tail['lines'] if 'total=1' in line],
'entry': launched['body']['entry']}, ensure_ascii=False), flush=True)
send(process, 6, 'disconnect')
wait_response(process, buffer, 'disconnect', 10)
finally:
if process.poll() is None: process.terminate()
try: _, stderr = process.communicate(timeout=8)
except subprocess.TimeoutExpired:
process.kill()
_, stderr = process.communicate()
if stderr:
print(stderr.decode(errors='replace')[-3000:], file=sys.stderr)
if __name__ == '__main__':
try: main()
except (RuntimeError, TimeoutError, OSError, KeyError, ValueError) as error:
print('macro-log-probe: '+str(error), file=sys.stderr)
sys.exit(1)