Жизненный цикл
Ниже описан текущий жизненный цикл модуля в termin-modules.
1. discover
ModuleRuntime::discover(project_root) рекурсивно обходит дерево проекта и ищет:
*.module*.pymodule
Для каждого файла:
- дескриптор парсится через
ModuleDescriptorParser - создаётся
ModuleSpec - в runtime добавляется
ModuleRecordсо статусомDiscovered
Во время поиска пропускаются служебные директории:
build__pycache__- скрытые директории
2. построение порядка загрузки
Перед load_all() runtime строит порядок загрузки по dependencies.
Сейчас используется обычная topological sort:
- если зависимость отсутствует, загрузка завершается ошибкой
- если найден цикл, загрузка завершается ошибкой
- модуль грузится только после всех своих зависимостей
3. load
ModuleRuntime::load_module(name) делает следующее:
- находит
ModuleRecord - проверяет, что все зависимости уже загружены
- выбирает backend по
ModuleKind - вызывает integration hook
before_load - вызывает backend
load(...) - переводит модуль в
LoadedилиFailed - публикует событие
4. load для C++ модуля
CppModuleBackend:
- читает
CppModuleConfig - если указан
build.command, запускает сборку в директории дескриптора - проверяет наличие
build.output - загружает shared library через
dlopenилиLoadLibrary - ищет символ
module_init - если символ найден, вызывает его
- сохраняет native handle в
CppModuleHandle
Важно:
- глобальные статические конструкторы shared library вызываются загрузчиком ОС при
dlopen/LoadLibrary module_initэто дополнительная явная точка входа поверх static initialization
5. load для Python модуля
PythonModuleBackend:
- инициализирует embedded Python, если он ещё не поднят
- добавляет
rootвsys.path - импортирует все пакеты из
packages - сохраняет список импортированных модулей и добавленных путей в
PythonModuleHandle
6. unload
ModuleRuntime::unload_module(name):
- проверяет, что модуль находится в состоянии
Loaded - вызывает integration hook
before_unload - вызывает backend
unload(...) - очищает
handle - переводит модуль в
Unloaded - публикует событие
Для C++:
- если найден
module_shutdown, он вызывается - затем shared library выгружается
Для Python:
- импортированные модули удаляются из
sys.modules - добавленные пути удаляются из
sys.path
7. reload
ModuleRuntime::reload_module(name) сейчас реализован как orchestration-операция:
- публикуется событие
Reloading - если модуль был загружен, выполняется
unload_module(name) - затем выполняется
load_module(name) - после успешной перезагрузки вызывается integration hook
after_reload
То есть сейчас у backend-ов нет отдельного специализированного reload; runtime собирает его из unload + load.