Entendre les CMakeLists

Familiaritzant-nos amb com funcionen els fitxers CMakeLists.txt

CMake

En la nostra guia d'aprenentatge introductòria, emprem el CMake com el sistema de compilació per a la nostra aplicació, però només parem molta atenció a un dels nostres fitxers CMakeLists.txt. Aquí, repassarem com funcionen amb una mica més de detall.

El CMake és útil perquè ens permet automatitzar gran part de les coses que s'han de fer abans de la compilació.

El CMakeLists.txt arrel

És possible que recordeu aquest fitxer CMakeLists.txt de la primera guia d'aprenentatge:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
cmake_minimum_required(VERSION 3.20)
project(kirigami-tutorial)

find_package(ECM 6.0.0 REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})

include(KDEInstallDirs)
include(KDECMakeSettings)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(ECMFindQmlModule)
include(ECMQmlModule)

find_package(Qt6 REQUIRED COMPONENTS
    Core
    Quick
    Test
    Gui
    QuickControls2
    Widgets
)

find_package(KF6 REQUIRED COMPONENTS
    Kirigami
    I18n
    CoreAddons
    QQC2DesktopStyle
    IconThemes
)

ecm_find_qmlmodule(org.kde.kirigami REQUIRED)

add_subdirectory(src)

install(PROGRAMS org.kde.tutorial.desktop DESTINATION ${KDE_INSTALL_APPDIR})

feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

La primera línia, cmake_minimum_required() estableix la versió del CMake que es cridarà.

Després d'això, project(kirigami-tutorial) defineix el nom del projecte.

Després arribem a una secció on incloem una sèrie de paràmetres necessaris de CMake i del KDE fent servir extra-cmake-modules. Proporcionen un conjunt d'utilitats:

  • KDEInstallDirs proporciona variables d'utilitat com ara ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}, ${KDE_INSTALL_QMLDIR}, ${KDE_INSTALL_BINDIR} i ${KDE_INSTALL_LIBDIR}.
  • KDECMakeSettings proporciona coses com CMAKE_AUTORCC ON, un objectiu uninstall que es pot fer servir amb cmake --build build/ --target uninstall, i ENABLE_CLAZY.
  • KDECompilerSettings proporciona un estàndard C++ mínim, indicadors del compilador com -pedantic, i macros de millors pràctiques com -DQT_NO_CAST_FROM_ASCII per a necessitar conversions explícites com QStringLiteral().
  • ECMFindQmlModule proporciona una manera d'assegurar que la dependència de QML en temps d'execució es troba en temps de compilació.
  • ECMQmlModule proporciona ordres del CMake com ecm_add_qml_module() i ecm_target_qml_sources().

La secció següent és important, perquè especifica quines dependències portarem en temps de compilació. Vegem el primer:

13
14
15
16
17
18
19
20
21
22
23
24
25
26
find_package(Qt6 REQUIRED COMPONENTS
    Core
    Quick
    Test
    Gui
    QuickControls2
    Widgets
)

find_package(KF6 REQUIRED COMPONENTS
    Kirigami
    I18n
    CoreAddons
    QQC2DesktopStyle
  • find_package() cerca i carrega la biblioteca externa i els seus components.
  • REQUIRED fa saber al CMake que surti amb un error si no s'ha pogut trobar el paquet.
  • COMPONENTS és un paràmetre que precedeix als components específics del marc de treball que incloem.
  • Cada paraula després de COMPONENTS es refereix a un component específic de la biblioteca.

La línia d'instal·lació instrueix al CMake que instal·li el fitxer «desktop» a ${KDE_INSTALL_APPDIR}, que al Linux es tradueix com $XDG_DATA_DIRS/applications, normalment /usr/share/applications, i en el Windows es tradueix com C:/Program Files/${PROJECT_NAME}/bin/data/applications:

32
add_subdirectory(src)

La línia final permet que el CMake imprimeixi quins paquets ha trobat, i fa que la compilació falli completament si troba un error:

34
install(PROGRAMS org.kde.tutorial.desktop DESTINATION ${KDE_INSTALL_APPDIR})

I a sobre d'això, add_subdirectory(src) a punta el CMake en el directori src/, a on troba un altre fitxer CMakeLists.txt.

src/CMakeLists.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
add_executable(kirigami-hello)

ecm_add_qml_module(kirigami-hello
    URI
    org.kde.tutorial
)

target_sources(kirigami-hello
    PRIVATE
    main.cpp
)

ecm_target_qml_sources(kirigami-hello
    SOURCES
    Main.qml
)

target_link_libraries(kirigami-hello
    PRIVATE
    Qt6::Quick
    Qt6::Qml
    Qt6::Gui
    Qt6::QuickControls2
    Qt6::Widgets
    KF6::I18n
    KF6::CoreAddons
    KF6::IconThemes
)

install(TARGETS kirigami-hello ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

Mentre que el primer fitxer gestionava metadades i cercava biblioteques, aquest consisteix a gestionar dependències i instal·lar l'aplicació. Té les crides següents del CMake:

  • add_executable() crea l'objectiu executable que farem servir per a executar el projecte.
  • ecm_add_qml_module() crea un objectiu de mòdul QML al qual es podrà accedir via la importació «org.kde.tutorial».
  • target_sources() afegeix fitxers de codi font C++ a l'objectiu executable.
  • ecm_target_qml_sources() afegeix fitxers QML al mòdul.
  • target_link_libraries() enllaça les biblioteques C++ utilitzades en el nostre codi amb el nostre executable. El Kirigami no s'inclou aquí perquè només estem utilitzant el seu mòdul QML.
  • install() instal·la l'executable en el sistema.

La documentació de les dues ordres ECM es pot trobar a l'API dels extra-cmake-modules per a l'ECMQmlModule.

La crida a ecm_add_qml_module() s'ha fet servir aquí per a modificar l'objectiu de l'executable del codi font C++ tradicional i convertir-lo en alguna cosa que pugui acceptar fitxer QML i codi font C++ source que sigui accessible des del QML en el que s'ha cridat usant l'executable com a objectiu de reserva per a un mòdul QML. Això vol dir que els fitxers QML s'executen directament com a part de l'aplicació, que sovint és el cas de les aplicacions.

També podeu crear un mòdul QML separat que no usi l'executable com a objectiu de reserva utilitzant ecm.add.qml.module(). En aquest cas, hauríeu de crear un objectiu de biblioteca utilitzant add.library(), enllaçar-lo a un objectiu executable existent utilitzant target_link_libraries(), i a més d'instal·lar la biblioteca amb install() haureu de finalitzar el mòdul QML amb ecm_finalize_qml_module() perquè pugui generar dos fitxers: qmldir i qmltypes. Aquests fitxers són utilitzats per les aplicacions QtQuick per a trobar mòduls QML separats.

El mètode per a crear un mòdul QML separat s'exemplifica millor a Usar fitxers separats.

Aquests són afegits proporcionats per extra-cmake-modules per a fer que l'ús del registre declaratiu de les Qt faciliti (la substitució als fitxers de recursos de les Qt).

La documentació de les tres ordres ECM es pot trobar a l'API dels extra-cmake-modules per a l'ECMQmlModule.

src/components/CMakeLists.txt

A la guia d'aprenentatge sobre com dividir el codi en fitxers separats, es va introduir un fitxer CMake nou per a permetre mòduls QML separats:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
add_library(kirigami-hello-components)

ecm_add_qml_module(kirigami-hello-components
    URI "org.kde.tutorial.components"
    GENERATE_PLUGIN_SOURCE
)

ecm_target_qml_sources(kirigami-hello-components
    SOURCES
    AddDialog.qml
    KountdownDelegate.qml
)

ecm_finalize_qml_module(kirigami-hello-components)

install(TARGETS kirigami-hello-components ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})

El requisit perquè aquest fitxer sigui llegit pel CMake és afegir una crida a add_subdirectory() en el src/CMakeLists.txt apuntant-hi.

Creem un objectiu nou anomenat kirigami-hello-components i després el convertim en un mòdul QML utilitzant ecm_add_qml_module() amb el nom d'importació org.kde.tutorial.components i afegim els fitxers QML pertinents.

La crida a add_library() genera un objectiu nou anomenat kirigami-hello-components. Aquest objectiu tindrà el seu conjunt propi de fitxers de codi font, fitxers en QML, enllaçarà les seves pròpies biblioteques i així successivament, però necessitarà estar vinculat a l'executable, però una vegada compilat necessitarà estar vinculat a l'executable creat en el src/CMakeLists.txt. Això es fa afegint el nom de destinació a la llista de biblioteques que s'enllaçaran a l'executable a target_link_libraries().

La crida a ecm_add_qml_module() canvia la biblioteca per a permetre que accepti fitxers QML com abans, però aquesta vegada cal usar GENERATE_PLUGIN_SOURCE. Quan l'executable es fa servir com a objectiu de reserva (com amb kirigami-hello) no cal generar codi del connector ja que està construït dins l'executable; amb mòduls QML separats com kirigami-hello-components és necessari el codi del connector.

El qt_add_qml_module() de les Qt originals generen de manera predeterminada un connector junt amb el mòdul QML, però l'ecm_add_qml_module() de KDE no ho fa per compatibilitat cap enrere.

Una altra cosa que és necessària per als mòduls QML separats és finalitzar l'objectiu. Això significa principalment que el CMake genera dos fitxers, qmldir i qmltypes, que descriuen els mòduls QML que tenim i exporten els seus símbols per al seu ús a la biblioteca. Són importants quan s'instal·la l'aplicació perquè l'executable que s'està executant pugui trobar on són els fitxers QML per a cada mòdul, de manera que s'afegeixen automàticament a l'objectiu.

A continuació, podeu instal·lar l'objectiu com abans.

La pròxima vegada que necessiteu afegir més fitxers QML, recordeu d'incloure'ls en aquest fitxer. Els fitxers C++ que utilitzen la paraula clau QML_ELEMENT que veurem més tard a la guia d'aprenentatge també es poden afegir aquí utilitzant target_sources(). Podeu separar lògicament el codi creant més mòduls QML amb importacions diferents segons calgui.

Aquesta configuració serà útil en desenvolupar la majoria de les aplicacions escrites amb el Kirigami.