Отладчик
Флаг -g (или --отладка) встраивает в объектный файл настоящую
DWARF-отладочную информацию через LLVM DebugInfoBuilder — тот же
самый механизм, которым пользуется clang для C/C++. Никакого
собственного, отдельного инструмента отладки при этом не появляется —
запускается уже установленный lldb или gdb, как для любой
другой скомпилированной программы:
запустить программа.код -g -c
lldb ./программа
# (b программа.код:10 — точка останова по номеру строки
# run — запустить
# next / step — шаг с обходом/входом в вызовы
# bt — стек вызовов
# continue)
Работает без каких-либо ограничений:
- Точки останова по номеру строки (
b файл.код:N) — для любой функции
и метода программы, включая тело параллельно ... конец.
- Пошаговое выполнение (
next/step/continue). - Полноценный стек вызовов (
bt) с настоящими именами функций/методов
«Сферы» на каждом уровне.
- Просмотр исходного кода прямо в отладчике (строка
-> Nперед
текущей позицией).
✅ Проверено напрямую в этой среде разработки: и lldb (18.1.3), и gdb
(15.1) корректно останавливаются на нужной строке, шагают по коду и
строят стек вызовов через несколько функций подряд, включая переход из
потока параллельно обратно в породившую его функцию. Каждый
собранный с -g объектный файл дополнительно прогоняется через
opt -passes=verify в рамках тестирования — эта проверка поймала (и
позволила исправить) два реальных бага в самой генерации debug-info,
прежде чем они попали бы к пользователю языка (см. подробности и то,
как именно они проявлялись, в ИСТОРИЯ_РАЗРАБОТКИ.md).
⚠️ Честно осталось на будущее (не реализовано в этой версии):
просмотр значений локальных переменных ПО ИМЕНИ (print х,
frame variable) пока не поддержан — компилятор не описывает точный
DWARF-тип для локальных переменных и параметров. Причина не в лени, а
в объёме: для этого понадобилось бы построить полноценное
DWARF-описание (DIType) для КАЖДОГО типа языка — не только целое/
дробное/верно, но и текст (показывать как C-строку или как сырой
указатель?), пользовательские структуры (с именами и типами полей,
включая вложенные и рекурсивные поля), Список из T/Словарь из К и З
(обобщённые контейнеры) и контракты (толстые указатели
{данные, vtable}) — то есть отдельная, довольно большая по объёму
работа, а не расширение уже сделанного. lldb/gdb всё равно способны
показать сырые байты по известному адресу (x/8xb $rsp+...), просто
не «красиво», по имени переменной с типом «Сферы».
На macOS дополнительно нужен шаг dsymutil после сборки — формат
Mach-O, в отличие от Linux/ELF, не встраивает debug-info прямо в
исполняемый файл, оставляя её в .o; dsymutil собирает из неё
отдельный .dSYM-бандл, без которого lldb на Mac не найдёт номера
строк. Компилятор делает это автоматически при -g на macOS (см.
слинковать_исполняемый_файл в src/main.rs) — ⚠️ этот шаг физически
не тестировался (песочница для разработки компилятора — Linux, без
доступа к macOS); сам механизм — стандартный, документированный Apple
инструмент, но перепроверить его на реальном Mac ещё стоит.