Imported from Dxvxkin/DxvUI (
AGENTS.md). Install upstream withnpx skills add Dxvxkin/DxvUI. Copyright stays with the author.
AGENTS.md
C++23 immediate-mode UI library built on SDL2 (SDL2, SDL2_ttf), spdlog, GTest. All code lives in namespace
DxvUI.
Build
- Toolchain: CMake + Ninja; компилятор не закреплён в пресетах — CMake берёт доступный (Linux: системный gcc/clang;
Windows: любой однородный MinGW-тулчейн на PATH, например bundled с CLion или scoop
mingw-winlibs-ucrt). FetchContent-депсы собираются тем же компилятором, что и проект. Зависимости — политика find-or-fetch (cmake/deps.cmake): каждая сначала ищется черезfind_packageв системе, а если не найдена — тянетсяFetchContent-ом из исходников по замороженному тегу (URL на tag-архив + SHA256; каталог_deps/в дереве build'а). vcpkg не используется.- Linux: системные пакеты (
sudo apt install libsdl2-dev libsdl2-ttf-dev libspdlog-dev libgtest-dev) — configure мгновенный, ничего не качается. - Windows/MinGW: системных пакетов нет → deps скачиваются и собираются из исходников при первом configure
(SDL2, SDL2_ttf, freetype, spdlog, googletest; ~5–15 мин один раз). Fetched-дерево кэшируется в
cmake-build-*/_deps/, пересборка не качает заново. - Windows: первый configure хочет доверенные CA-сертификаты. FetchContent качает через встроенный CMake-curl
(GnuTLS), которому на Windows неоткуда взять trust anchors → качалка падает (
SSL certificate verification failed ... no trust anchors configured). Перед первымcmake --preset ...задайте системный CA-бандл, например Git-овский:$env:SSL_CERT_FILE = "C:\Program Files\Git\usr\ssl\certs\ca-bundle.crt". Не выключайте проверку через-DCMAKE_TLS_VERIFY=OFF. _deps/живёт внутри каждого бинарьного каталога (cmake-build-debug/_deps,cmake-build-release/_deps), а не в общем корне: у FetchContent каталог-build(сCMAKE_BUILD_TYPE«кто первый») лежит тоже в базовом каталоге. Общий базовый корень заставил бы release-сборку линковать Debug-депсы (искажает калибровку бенчмарка) и конфликтовал бы при смене тулчейна. Цена — одноразовая перекачка/пересборка в каждом каталоге (~5–15 мин); при желании можно вынести качалку в общий корень черезSOURCE_DIRвFetchContent_Declare, оставивBINARY_DIRв своём бинарьном каталоге (намеренно не сделано по умолчанию).
- Linux: системные пакеты (
- Конфигурация — через
CMakePresets.json:debug/release(Windows) иlinux-debug/linux-release(Linux); binaryDir'ы совпадают с CLion-овскими (cmake-build-{debug,release}/, gitignored). CLion работает как раньше (свои профили, те же каталоги); VS Code — расширение CMake Tools (пресеты подхватываются автоматически) + clangd (compile_commands.json копируется в корень репо таргетомcopy_compile_commands).
# Windows: configure + build + tests
cmake --preset debug # или release; на Linux: linux-debug / linux-release
cmake --build cmake-build-debug
ctest --test-dir cmake-build-debug
# или напрямую (GTest-тесты автодискаверятся через gtest_discover_tests)
./cmake-build-debug/bin/DxvUITests.exe
# один набор тестов: ... --gtest_filter=LayoutManagerTests.* (или ctest -R <regex>)
# пересборка по существующему кэшу — просто build:
cmake --build cmake-build-release
- Transfertные флаги:
-DDXVUI_FORCE_FETCH_DEPS=ON— игнорировать систему и тянуть всё из исходников (ручная проверка fetch-пути; CI в репозитории нет);-DFETCHCONTENT_FULLY_DISCONNECTED=ON— офлайн-переконфигурация из уже скачанного_deps(без сети).
- SDL_ttf поверх фетчнутого freetype:
cmake/deps.cmakeтянет freetype и подкладывает обёрткуcmake/FindFreetype.cmake, редиректящуюFreetype::Freetypeна собранный таргет (активируется только вокруг сборки SDL_ttf, системный поиск Linux не затрагивает).
Работа между Windows и Linux (git-воркфлоу)
Обе машины работают напрямую с единой веткой master на GitHub (единственный источник правды); локальных «OS-веток»
нет.
- Правила:
- перед началом работы и перед пушем — обязательно стянуть свежую историю:
git pull --ff-only(Windows) /git pull --rebase(Linux); - никогда не использовать
git push --force; - конфликты разрешаются локально, правки пушатся отдельными осмысленными коммитами.
- перед началом работы и перед пушем — обязательно стянуть свежую историю:
- Windows: работа на
master(или в короткоживущей ветке с fast-forward-мержем в master); перед пушем сноваgit pull --ff-only— пуш всегда идёт fast-forward. - Linux: работа на отслеживаемом
origin/master; перед пушемgit pull --rebase— локальные коммиты накладываются поверх свежих чужих, история остаётся линейной и пуш проходит без non-fast-forward. - Синхронизация
AGENTS.mdи любых правок между машинами происходит сама через пул/пуш; общая документация держится в актуальном виде на GitHub.
Release build (for performance work)
cmake-build-release/ is a second, separate build dir:
cmake --preset release
cmake --build cmake-build-release
Packaging / consumption by third parties
cmake --install <builddir> --prefix <dir>ставит headers (include/DxvUI/*), статическую библиотеку и CMake-пакет (lib/cmake/DxvUI:DxvUIConfig.cmake,DxvUIConfigVersion.cmake,DxvUITargets.cmake, namespaceDxvUI::). Версия пакета берётся изproject(... VERSION ...)(SameMajorVersion).- Подключение снаружи:
find_package(DxvUI REQUIRED CONFIG)+target_link_libraries(app PRIVATE DxvUI::DxvUI); публичные зависимости (SDL2/SDL2_ttf/spdlog) подтягиваются черезfind_dependency. - Упаковка/export доступна только когда зависимости пришли из системы (импортированные таргеты). При
FetchContent-фетче (
cmake/deps.cmakeставитDXVUI_DEPS_EXPORTABLE=FALSE) экспорт пропускается — реальные таргеты из_depsне попадают в экспорт-сет; собирается только статика + headers. - Потребитель должен иметь собственные SDL2/SDL2_ttf/spdlog (консольному приложению нужен
#define SDL_MAIN_HANDLEDдо включения заголовков DxvUI — зонтичныйDxvUI/DxvUI.hтянет<SDL.h>, который на Windows редиректитmain→SDL_main). - Dev-experience в репо: в
bin/рядом с экзешниками копируются MinGW-runtime DLL (libstdc++-6/libgcc_s_seh-1/libwinpthread-1, таргетdxvui_mingw_runtime) и рантайм-DLL фетчнутых SDL2/SDL2_ttf (dxvui_deploy_fetched_runtime_dlls, см.cmake/deps.cmake) — собранные бинарники запускаются двойным кликом без настройки PATH.
Performance evaluation
Benchmark: examples/benchmark.cpp → DxvUIBenchmark.exe (both build dirs).
- Use the Release build. Debug numbers are meaningless (a 100–1000x slowdown hides real regressions). Debug A/B is only for confirming direction.
- Benchmark protocol:
- close all other apps, power plan High Performance;
- run
DxvUIBenchmark.exe --repeats 3(each scenario reports mean/median/min/p95 over all repeats); - vsync is off by default in the benchmark so frame-phase timing is not quantized to the display rate (
--vsyncopts back in); - compare medians, not means; treat
>= 10%on a metric as a regression.
- Automated A/B:
scripts/compare.ps1runs two builds with--json, prints a delta table and exits 1 if any metric regressed >= 10%:powershell -ExecutionPolicy Bypass -File scripts/compare.ps1 ` -Baseline cmake-build-debug\DxvUIBenchmark.exe ` -New cmake-build-release\DxvUIBenchmark.exe -Repeats 3 - Scenario filter:
--scenario=frames,scroll,hit,text,clip,micro(comma-separated prefixes).text= dynamic labels (uncached rasterization + texture-cache growth),clip= nestedclipContent,micro= raw primitives (incl. uncachedrasterize).getTextureCacheCount()exposes the cache size for growth checks — the texture cache is LRU-bounded (default 1024 entries), so in thetext/microscenarios growth plateaus at the cap instead of growing linearly in unique (font, text, color) keys. - JSON:
--jsonprints a---JSON---{...}---JSON---block at the end (all metrics, mean/median/min/max/p95/n), whichcompare.ps1parses.
Gotchas
- No source globbing. Every
.cppis explicitly listed inCMakeLists.txttarget_sources(libDxvUI, test exeDxvUITests). Adding a source file without editing CMakeLists means it silently won't build. - Umbrella header
DxvUI/DxvUI.hincludes all public headers. Keep it in sync when adding a new public header. - Сборка держится на нуле предупреждений (
-Wall -Wextra -Wpedantic//W4). GCC-варнинг-Wmissing-field-initializersна designated-инициализаторах optional-агрегатов (StyleRule,ComputedLayoutStyleвstyle/Style.h) глушится NSDMI= std::nullopt, а не-Wno-.../прагмами. - stb_image — единственный вендоренный деп (в отличие от остальных, не find-or-fetch):
third_party/stb/stb_image.h; TU с реализацией —src/stb_image_impl.cpp(STB_IMAGE_IMPLEMENTATION), вызывается изsrc/core/ImageData.cpp. Публичные заголовки stb не включают — консьюмерам пакета он не нужен. - Examples используют общий DxvUI-agnostic хост
examples/App.h(DxvUIEx::SdlApp: окно/рендерер/цикл; пример сам владеет Scene/SDLRenderer) иexamples/FpsOverlay.h. Новый пример — подкласс SdlApp +add_dxvui_example(...)в CMakeLists (сам добавит warnings, рантайм-DLL иSDL2::SDL2mainна Windows).DXVUI_FRAMES=Nограничивает число кадров — для скриптового прогона. - SDL entry point. The example defines
extern "C" int SDL_main(...)and linksSDL2::SDL2main; SDL2 redefinesmainon Windows. - Font selection. Styles pick a font by logical family (
.fontFamily = "Sans"), resolved to a platform font file viagetDefaultFontFamilyPath()(incore.h); custom families go throughITextEngine::registerFontFamily(). Direct low-level engine calls useDxvUI::getDefaultFontPath()(incore.h). - Один целостный тулчейн — и бинарники самодостаточны. FetchContent-депсы (SDL2, SDL2_ttf, freetype, spdlog,
googletest) собираются тем же компилятором, что и проект. MinGW-runtime и DLL депсов кладутся в
bin/из этой же сборки (dxvui_mingw_runtime+dxvui_deploy_fetched_runtime_dlls: SDL2, SDL2_ttf, spdlog, freetype), поэтому экзешники запускаются двойным кликом без настройки PATH; пересечения разных рантаймов не возникает. Старый сценарий vcpkg-времён (exe сlibspdlogd.dllгрузил чужойlibstdc++-6.dllиз PATH →0xC0000139) больше не воспроизводится. - Windows: следите, чтобы на PATH не стоял «скомканный» набор тулчейнов. CMake берёт первый подходящий компилятор
из PATH; соседство scoop
llvmиmingw-winlibs-ucrtзаставляет его выбратьclang++/llvm-rc, которые без Visual Studio нерабочие (detect broken,winresrc.h not found). Достаточно выстроить PATH нужного MinGW первым (в CLion он подставляется сам) либо задать компиляторы по именам без путей:cmake --preset debug -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_RC_COMPILER=windres. Жёсткий абсолютный путь (раньше этого требовал vcpkg) больше не нужен. Проверено на Windows: CLion GCC 15.2 (debug/release) и scoopmingw-winlibs-ucrtGCC 16.1 — 385/385 тестов. - MSVC-путь (fetch-сборка под
cl) не проверялся: код имеет ветки/W4,dxvui_mingw_runtimeпропускается, но отдельного прогона не было.
Conventions
- Formatting:
.clang-format(ColumnLimit 100, indent 4,PointerAlignment: Left, includes sorted/regrouped). Project was bulk-formatted in commit9846733; run clang-format on touched files. .clang-tidyis generated from CLion inspections — do not hand-maintain.- Headers under
include/DxvUI/, impls insrc/mirroring the same subdirs (widgets/,containers/,interfaces/,backend/,text/,style/,layout/). AllI*abstractions live ininterfaces/; all SDL/backend concrete implementations live inbackend/. - Layout/arrange logic was recently extracted from
SceneNodeinto the container classes — put measure/arrange overrides in containers, notSceneNode. - Commit messages and some comments are in Russian; match that when relevant.
- Планы развития —
docs/TRACKER.md: единый трекер «сделано / осталось» по API-виджетам-событиям, рендеру и авто-кешу/батчингу; детальная история и обоснования — в git-истории (документы-предшественники удалены).