Архитектура Qt-приложений + CMake

Автор: | 10 февраля, 2026

Цели архитектуры Qt-проекта

Хороший Qt-проект:

  • изолирует UI от бизнес-логики
  • минимизирует зависимости между модулями
  • легко тестируется без GUI
  • собирается на всех платформах
  • масштабируется до сотен таргетов
  • допускает плагины
  • интегрируется в CI/CD

CMake здесь — не просто билд-система, а средство описания архитектуры.


Слоистая структура (Layered Architecture)

Типовая схема:

app/
 ├─ ui/          (Qt Widgets / QML)
 ├─ domain/      (бизнес-логика)
 ├─ services/    (сетевые/IO/БД)
 ├─ infrastructure/
 ├─ plugins/
 └─ tests/

Каждый слой — отдельная библиотека.


Модульность через targets

Root:

add_subdirectory(domain)
add_subdirectory(services)
add_subdirectory(ui)
add_subdirectory(app)

domain/CMakeLists.txt:

add_library(domain STATIC
    order.cpp
    order.h
)

target_include_directories(domain PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(domain PUBLIC Qt6::Core)

ui:

add_library(ui STATIC mainwindow.cpp mainwindow.h)

target_link_libraries(ui
    PRIVATE Qt6::Widgets
    PUBLIC domain
)

app:

qt_add_executable(myapp main.cpp)

target_link_libraries(myapp PRIVATE ui services)

Dependency Rule

UI → Services → Domain

Domain не знает о Qt Widgets.

Допустимо:

  • QtCore
  • std

Недопустимо:

  • GUI
  • Network UI

MVVM / MVP в Qt

Qt легко реализует MVVM:

View (QML)
   ↓
ViewModel (QObject)
   ↓
Domain

ViewModel — библиотека:

add_library(viewmodels STATIC user_vm.cpp)
target_link_libraries(viewmodels PUBLIC domain Qt6::Core)

Plugins Architecture

Qt поддерживает runtime-плагины.

plugins/logger:

qt_add_plugin(logger_plugin)

target_link_libraries(logger_plugin PRIVATE Qt6::Core)

Интерфейс:

class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void log(QString msg) = 0;
};

Q_DECLARE_INTERFACE(ILogger, "org.example.Logger")

QML-модули как отдельные targets

qt_add_qml_module(gui
    URI My.App.GUI
    VERSION 1.0
    QML_FILES Main.qml
)

Test-friendly архитектура

domain/tests:

add_executable(domain_tests test_order.cpp)
target_link_libraries(domain_tests PRIVATE domain Catch2::Catch2WithMain)

add_test(NAME domain COMMAND domain_tests)

Presets для Qt-проектов

{
  "configurePresets": [
    {
      "name": "linux-debug",
      "generator": "Ninja",
      "binaryDir": "build/linux-debug",
      "cacheVariables": {
        "CMAKE_BUILD_TYPE": "Debug",
        "QT_QPA_PLATFORM": "offscreen"
      }
    }
  ]
}

Монорепозитории и superbuild

superbuild/
 ├─ CMakeLists.txt
 └─ external/

Использование FetchContent:

FetchContent_Declare(
    mylib
    GIT_REPOSITORY ...
)