Понимание CMakeLists
CMake
Во вводном руководстве в качестве системы сборки приложения использовался CMake, однако подробно был рассмотрен лишь один из файлов CMakeLists.txt. Здесь немного подробнее разбирается, как он работает.
CMake полезен, поскольку позволяет автоматизировать большую часть действий, которые необходимо выполнить перед компиляцией.
Корневой файл CMakeLists.txt
Возможно, этот файл CMakeLists.txt уже встречался в первом руководстве:
| |
Первая строка, cmake_minimum_required(), задаёт версию CMake, которая будет использоваться.
После этого project(kirigami-tutorial) задаёт имя проекта.
Затем идёт раздел, в котором с помощью extra-cmake-modules подключается ряд необходимых параметров CMake и KDE. Они предоставляют набор полезных утилит:
- KDEInstallDirs предоставляет удобные переменные, такие как
${KDE_INSTALL_TARGETS_DEFAULT_ARGS},${KDE_INSTALL_QMLDIR},${KDE_INSTALL_BINDIR}и${KDE_INSTALL_LIBDIR}. - KDECMakeSettings предоставляет такие возможности, как
CMAKE_AUTORCC ON, цельuninstall, которую можно использовать сcmake --build build/ --target uninstall, иENABLE_CLAZY. - KDECompilerSettings задаёт минимальный стандарт C++, флаги компилятора, такие как
-pedantic, и макросы рекомендуемых практик, например-DQT_NO_CAST_FROM_ASCII, требующие явных преобразований, таких какQStringLiteral(). - ECMFindQmlModule позволяет убедиться, что зависимость QML времени выполнения будет найдена во время сборки.
- ECMQmlModule предоставляет команды CMake, такие как
ecm_add_qml_module()иecm_target_qml_sources().
Следующий раздел важен, так как в нём указывается, какие зависимости будут подключены во время сборки. Рассмотрим первую:
| |
- find_package() находит и загружает внешнюю библиотеку и её компоненты.
REQUIREDпредписывает CMake завершить работу с ошибкой, если пакет не найден.COMPONENTS— параметр, предшествующий конкретным компонентам подключаемого фреймворка.- Каждое слово после
COMPONENTSобозначает конкретный компонент библиотеки.
Примечание
Если требуется добавить в приложение какой-либо из компонентов, перечисленных в документации по API KDE, сведения о добавлении компонента с помощью CMake приведены на правой боковой панели. Например, для Kirigami там будет указано что-то вроде find_package(KF6Kirigami), которое после добавления ECM превращается в:
find_package(KF6 COMPONENTS Kirigami)Обратите внимание на подключаемые компоненты: если пропустить хотя бы один из используемых в приведённом коде компонентов, приложение не соберётся.
Строка install указывает CMake установить файл .desktop в ${KDE_INSTALL_APPDIR}, что в Linux соответствует $XDG_DATA_DIRS/applications, обычно /usr/share/applications, а в Windows — C:/Program Files/${PROJECT_NAME}/bin/data/applications:
| |
Последняя строка позволяет CMake вывести, какие пакеты найдены, а при возникновении ошибки сборка немедленно прерывается:
| |
А выше этого add_subdirectory(src) указывает CMake на папку src/, где обнаруживается ещё один файл CMakeLists.txt.
src/CMakeLists.txt
| |
Первый файл отвечал за метаданные и поиск библиотек, а этот — за обработку зависимостей и установку приложения. В нём используются следующие вызовы CMake:
- add_executable() создаёт исполняемую цель, которая будет использоваться для запуска проекта.
ecm_add_qml_module()создаёт цель модуля QML, доступную через импорт «org.kde.tutorial».- target_sources() добавляет исходные файлы C++ в исполняемую цель.
ecm_target_qml_sources()добавляет файлы QML в модуль.- target_link_libraries() связывает используемые в коде библиотеки C++ с исполняемым файлом. Kirigami здесь не включён, поскольку используется только его модуль QML.
- install() устанавливает исполняемый файл в систему.
Документация по двум командам ECM приведена в API extra-cmake-modules для ECMQmlModule.
Здесь вызов ecm_add_qml_module() использован для изменения традиционной исполняемой цели с исходным кодом C++ и превращения её в нечто, способное принимать файлы QML и исходный код C++, доступный из QML, — это называется использованием исполняемого файла в качестве опорной цели модуля QML. Это означает, что файлы QML выполняются непосредственно как часть приложения, что для приложений обычное дело.
Можно также создать с помощью ecm_add_qml_module() отдельный модуль QML, который не использует исполняемый файл в качестве опорной цели. В этом случае создаётся цель библиотеки с помощью add_library(), она связывается с существующей исполняемой целью с помощью target_link_libraries(), а помимо установки библиотеки с помощью install() потребуется завершить модуль QML с помощью ecm_finalize_qml_module(), чтобы создать два файла: qmldir и qmltypes. Эти файлы используются приложениями QtQuick для поиска отдельных модулей QML.
Способ создания отдельного модуля QML нагляднее показан в руководстве Использование отдельных файлов.
Это дополнения, предоставляемые extra-cmake-modules для упрощения использования декларативной регистрации Qt (замены файлов ресурсов Qt).
Примечание
Эти библиотеки должны соответствовать компонентам, включённым в предыдущий файлCMakeLists.txt, иначе эти компоненты не будут включены, и приложение не соберётся.Документацию по всем трём командам можно найти в API extra-cmake-modules для ECMQmlModule.
src/components/CMakeLists.txt
В руководстве о том, как разделить свой код на отдельные файлы, был представлен новый файл CMake, позволяющий использовать отдельные модули QML:
| |
Чтобы CMake прочитал этот файл, в src/CMakeLists.txt нужно добавить вызов add_subdirectory(), указывающий на него.
Создаётся новая цель с именем kirigami-hello-components, которая затем преобразуется в модуль QML с помощью ecm_add_qml_module() под именем импорта org.kde.tutorial.components, и добавляются соответствующие файлы QML.
Вызов add_library() создаёт новую цель с именем kirigami-hello-components. У этой цели будет собственный набор файлов исходного кода и файлов QML, собственные библиотеки для компоновки и так далее, но после компиляции её нужно скомпоновать с исполняемым файлом, созданным в src/CMakeLists.txt. Для этого имя цели добавляется в список библиотек, которые будут скомпонованы с исполняемым файлом в target_link_libraries().
Вызов ecm_add_qml_module() изменяет библиотеку так, чтобы она, как и прежде, принимала файлы QML, но на этот раз требуется использовать GENERATE_PLUGIN_SOURCE. Когда исполняемый файл используется в качестве опорной цели (как в kirigami-hello), создавать код подключаемого модуля не требуется, поскольку он встроен в исполняемый файл; при отдельных модулях QML, таких как kirigami-hello-components, код подключаемого модуля необходим.
В вышестоящем Qt qt_add_qml_module() по умолчанию создаёт подключаемый модуль вместе с модулем QML, но ecm_add_qml_module() из KDE по умолчанию этого не делает для обратной совместимости.
Для отдельных модулей QML также необходимо завершить цель. В основном это означает, что CMake создаёт два файла, qmldir и qmltypes, которые описывают имеющиеся модули QML и экспортируют их символы для использования в библиотеке. Они важны при установке приложения, чтобы запускаемый исполняемый файл мог найти, где находятся файлы QML для каждого модуля, поэтому они автоматически добавляются к цели.
Затем достаточно установить цель, как и раньше.
Когда в следующий раз потребуется добавить дополнительные файлы QML, не забудьте включить их в этот файл. Файлы C++, в которых используется ключевое слово QML_ELEMENT, которое будет рассмотрено значительно позже в руководстве, также можно добавить здесь с помощью target_sources(). Код можно логически разделить, создав дополнительные модули QML с другими импортами по мере необходимости.
Эта настройка пригодится при разработке большинства приложений Kirigami.