Собственные расширения: триада подключает любую C-библиотеку
Помимо sqlite и xtp2, ваши собственные библиотеки вкомпилируются тем же способом — реестр спроектирован как «добавил запись — и всё», и каждый вход проверяется.
Обзор
39.1 Введение
Цель дизайна механизма одной фразой: новая библиотека = объявление, а не код. В исходниках хоста нет ни одной библиотечной ветки (if sqlite… else if xtp…) — реестр на этапе сборки генерирует заголовок агрегации символов xs_build_extensions.h, а в рантайме единообразно внедряется в TCC через XS_TccAddExtensions(). Это значит: подключение новой библиотеки не требует правок исходников хоста и границы расширения полностью определяются файлом объявления.
39.2 Триада
{
"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.
Скриптом через #ifdef XS_USE_MYLIB дайте две реализации (есть библиотека — через неё, нет — встроенную); компилируются оба варианта.
Добавьте для библиотеки тесты уровня плана и рантайма, включая обратное утверждение «не выбрано — недоступно».
Итоги
| Тезис | Вывод |
|---|---|
| Механизм | новая библиотека = триада + json-запись, хост без правок |
| Триада | исходники (вкомпиляция) + заголовок (в VFS) + таблица символов (внедрение в TCC) |
| Проверки | побеги путей / конфликты макросов / перекрытие заголовков / белый список полей |
| Тесты | уровень плана + уровень рантайма (с обратным утверждением недоступности) |
- справочник xrt · core — базовые соглашения типов, общие для исходников расширений, вкомпилируемых в хост