Глава 39 / 51
Том 5 · Расширения, эксплуатация и практика

Собственные расширения: триада подключает любую C-библиотеку

Помимо sqlite и xtp2, ваши собственные библиотеки вкомпилируются тем же способом — реестр спроектирован как «добавил запись — и всё», и каждый вход проверяется.

Обзор

Позиционирование: для разработчиков, желающих привести свои C-библиотеки в XServer. Результат — триада плюс одна регистрация; делайте по живым образцам sqlite/xtp2, а глава объясняет, зачем каждый шаг.

39.1 Введение

Цель дизайна механизма одной фразой: новая библиотека = объявление, а не код. В исходниках хоста нет ни одной библиотечной ветки (if sqlite… else if xtp…) — реестр на этапе сборки генерирует заголовок агрегации символов xs_build_extensions.h, а в рантайме единообразно внедряется в TCC через XS_TccAddExtensions(). Это значит: подключение новой библиотеки не требует правок исходников хоста и границы расширения полностью определяются файлом объявления.

39.2 Триада

Реальная запись extensions.json (дословно из репозитория)проверено на реальной машинеисточник: xserver/tools/extensions.json
{
  "mylib": {
    "macro": "XS_USE_MYLIB",                  /* ① макрос компиляции: переключатель видимости в скриптах */
    "headers": {"mylib.h": "lib/mylib.h"},     /* ② заголовок → отображение в VFS */
    "sources": [{"path": "lib/mylib.c",
                 "flags": ["-O2"]}],           /*    исходники, вкомпилируемые в хост (с флагами) */
    "symbols": "src/script/import_mylib.inc",  /* ③ таблица символов */
    "symbol_macro": "XS_MYLIB_SYMBOL"
  }
}

Связь триады: исходники — в хост (реализация в процессе), заголовок — в VFS (скрипт может включить объявления), таблица символов — в TCC (вызовы скрипта разрешаются по адресу в реализацию). Макрос XS_USE_MYLIB предопределяется и во вложенном компиляторе — скрипт может зондируовать доступность через #ifdef. Однозаголовочные библиотеки (стиль stb) несут переключатель реализации в поле defines (запись xtp2 — образец с XTP2_IMPLEMENTATION).

39.3 Проверки реестра

Реестр (xs_extensions.py) защитно проверяет каждый вход; кривая регистрация взрывается ещё на сборке:

ПроверкаОт чего страхует
source_path обязан существовать внутри проектапобег пути (подтягивание случайных файлов вне репозитория)
глобальная дедупликация feature-макросовдва расширения делят одно имя макроса
VFS-имена заголовков без .. и с межрасширительной уникальностьювзаимное перекрытие заголовков / пробег пути
белый список полейполе с опечаткой молча игнорируется
проверка формата имён макросов/библиотекгенерация нелегального кода

У этих проверок есть собственные юнит-тесты (один из 10 кейсов test_extensions.py — ровно «добавил демо-запись, сработало, ноль веток кода»).

39.4 Два уровня тестов

  • Уровень плана (test_extensions.py): разбор реестра, план сборки, связка таблицы символов и заголовков, защита публикации — чистая логика, секунды
  • Уровень рантайма (test_extensions_runtime.py): встроенные C-зонды внутри реально собранного XServer — настоящие вызовы API расширения, расширения доступны и во вложенном TCC, обратная проверка «в невыбранном варианте заголовков и символов действительно нет» (отказ компиляции + ошибка с именем)

Расширяя свою библиотеку, закройте оба уровня: уровень плана бережёт чистоту регистрации, уровень рантайма доказывает «вкомпилировано — реально работает; не вкомпилировано — реально отсутствует».

39.5 Контракт

  • Объявление: новая библиотека = триада + одна json-запись, хост без правок.
  • Согласованность: VFS-заголовок, таблица символов и исходники хоста обязаны быть одной версии — таблица с функциями, которых нет в заголовке, это бомба замедленного действия.
  • Тестирование: два уровня — определение приёмки расширения.

Частые ошибки

Таблица символов разошлась с заголовком
Симптом
Линковка скрипта падает (заголовок есть, символов нет) или в рантайме прыжок по дикой ссылке (символы есть, заголовок устарел).
Причина
После апгрейда библиотеки перегенерировали только одно из двух. Сделайте генерацию таблицы скриптом, меняющимся вместе с заголовком.
Забыта обёртка символ-макросом
Симптом
.inc таблицы символов ломает сборку хоста в безрасширительных вариантах.
Причина
Import-таблица обязана оборачиваться symbol_macro (сверьте стиль XS_SQLITE_SYMBOL в import_sqlite.inc) — символы расширения вкомпилируются в хост только в выбранных вариантах.

Упражнения

БазовыйРегистрация игрушечной библиотеки

Напишите однозаголовочную библиотеку add(int,int), зарегистрируйте по триаде и подтвердите через --list-extensions.

Приёмка: build.bat mylib успешно; скрипт с add возвращает верное.
ПродвинутыйЗондирование доступности

Скриптом через #ifdef XS_USE_MYLIB дайте две реализации (есть библиотека — через неё, нет — встроенную); компилируются оба варианта.

Приёмка: поведение default и mylib совпадает (источник разный).
ВызовОба уровня тестов

Добавьте для библиотеки тесты уровня плана и рантайма, включая обратное утверждение «не выбрано — недоступно».

Приёмка: прямое и обратное утверждения проходят; нарочно испорченная регистрация ловится уровнем плана.

Итоги

ТезисВывод
Механизмновая библиотека = триада + json-запись, хост без правок
Триадаисходники (вкомпиляция) + заголовок (в VFS) + таблица символов (внедрение в TCC)
Проверкипобеги путей / конфликты макросов / перекрытие заголовков / белый список полей
Тестыуровень плана + уровень рантайма (с обратным утверждением недоступности)
Что дальше по xrt
  • справочник xrt · core — базовые соглашения типов, общие для исходников расширений, вкомпилируемых в хост