Entendiendo CMakeLists
CMake
En nuestro tutorial de introducción hemos usado CMake como sistema de compilación para nuestra aplicación, aunque solo hemos prestado más atención a uno de nuestros archivos CMakeLists.txt
. Aquí vamos a profundizar un poco más sobre cómo funciona.
CMake es útil porque nos permite automatizar la mayoría de las cosas necesarias que hay que hacer antes de compilar.
El CMakeLists.txt raíz
Es posible que recuerde este archivo CMakeLists.txt
del primer tutorial:
|
|
La primera línea, cmake_minimum_required()
define la versión de CMake que se va a utilizar.
A continuación, project(kirigami-tutorial)
define el nombre del proyecto.
Luego llegamos a una sección donde incluimos una serie de preferencias necesarias de CMake y de KDE usando extra-cmake-modules. Estas proporcionan un conjunto de prácticas utilidades:
- KDEInstallDirs proporciona variables de conveniencia, como
${KDE_INSTALL_TARGETS_DEFAULT_ARGS}
,${KDE_INSTALL_QMLDIR}
,${KDE_INSTALL_BINDIR}
y${KDE_INSTALL_LIBDIR}
. - KDECMakeSettings proporciona cosas como
CMAKE_AUTORCC ON
, un objetivouninstall
que se puede usar concmake --build build/ --target uninstall
, yENABLE_CLAZY
. - KDECompilerSettings proporciona un estándar de C++ mínimo, indicadores del compilador (como
-pedantic
) y macros de buenas prácticas (como-DQT_NO_CAST_FROM_ASCII
para exigir conversiones explícitas, comoQStringLiteral()
). - ECMFindQmlModule proporciona un modo para asegurar que al compilar se encuentra una dependencia QML en tiempo de ejecución.
- ECMQmlModule proporciona órdenes de CMake como
ecm_add_qml_module()
yecm_target_qml_sources()
.
La siguiente sección es importante, ya que especifica las dependencias necesarias durante la compilación. Veamos la primera:
|
|
- find_package() encuentra y carga la biblioteca externa y sus componentes.
REQUIRED
indica a CMake que salga con un error si no se puede encontrar el paquete.COMPONENTS
es un parámetro que precede a los componentes específicos de la infraestructura que vamos a incluir.- Cada palabra tras
COMPONENTS
hace referencia a un determinado componente de la biblioteca.
Nota
If you are looking to add any components listed in the KDE API documentation to your application, you may check the right sidebar for how to add the component with CMake. For instance, for Kirigami, you will find something like find_package(KF6Kirigami)
, which with the addition of ECM becomes:
find_package(KF6 COMPONENTS Kirigami)
Preste mucha atención a los componentes incluidos, ya que si omite alguno de ellos en el código se detendrá la compilación de la aplicación.
La línea de instalación indica a CMake que instale el archivo de escritorio en ${KDE_INSTALL_APPDIR}
, que en Linux se traduce a $XDG_DATA_DIRS/applications
, normalmente /usr/share/applications
, y en Windows se traduce a C:/Program Files/${PROJECT_NAME}/bin/data/applications
:
|
|
La última línea permite que CMake liste los paquetes que ha encontrado y que haga que la compilación falle inmediatamente si se produce un error:
|
|
Y sobre ella, add_subdirectory(src)
hace que CMake se dirija al directorio src/
, donde encontrará otro archivo CMakeLists.txt
.
src/CMakeLists.txt
|
|
Mientras el primer archivo se encargaba de los metadatos y de encontrar bibliotecas, este se encargará de las dependencias y de instalar la aplicación. Contiene las siguientes llamadas de CMake:
- add_executable() crea el ejecutable de destino que usaremos para ejecutar nuestro proyecto.
ecm_add_qml_module()
crea un módulo QML de destino que será accesible mediante la importación de «org.kde.tutorial».- target_sources() añade los archivos de código fuente C++ al ejecutable de destino.
ecm_target_qml_sources()
añade archivos QML al módulo.- target_link_libraries enlaza las bibliotecas de C++ usadas en el código fuente con nuestro ejecutable. Kirigami no está incluido aquí porque estamos usando solo su módulo QML.
- install() instala el ejecutable en el sistema.
La documentación de las dos órdenes ECM se puede encontrar en la API de extra-cmake-modules para ECMQmlModule.
La llamada a ecm_add_qml_module()
se ha usado aquí para modificar el destino ejecutable del código fuente C++ tradicional y convertirlo en algo que pueda aceptar archivos QML y código fuente C++ al que se pueda acceder desde QML en lo que se denomina uso del ejecutable como destino de respaldo para un módulo QML. Esto significa que los archivos QML se ejecutan directamente como parte de la aplicación, como suele ser el caso de las aplicaciones.
También puede crear un módulo QML independiente que no use el ejecutable como destino de respaldo mediante ecm_add_qml_module()
. En este caso, crearía un destino de biblioteca mediante add_library(), lo enlazaría a un destino ejecutable existente mediante target_link_libraries()
y, además de instalar la biblioteca con install()
, deberá finalizar el módulo QML con ecm_finalize_qml_module() para que pueda generar dos archivos: qmldir
y qmltypes
. Las aplicaciones QtQuick usan estos archivos para buscar módulos QML independientes.
El método para crear un módulo QML separado se ejemplifica mejor en Uso de archivos separados.
Son adiciones proporcionadas por extra-cmake-modules para hacer que el uso del registro declarativo de Qt (el reemplazo de los archivos de recursos de Qt) sea más fácil.
Nota
Estas bibliotecas deben coincidir con los componentes que incluimos en nuestro archivoCMakeLists.txt
anterior; de lo contrario, estos componentes no se incluirán y nuestra aplicación no se compilará.La documentación de las tres órdenes se puede encontrar en la API de extra-cmake-modules para ECMQmlModule.
src/components/CMakeLists.txt
En el tutorial sobre cómo dividir el código en archivos separados, se introdujo un nuevo archivo CMake para permitir módulos QML separados:
|
|
El requisito para que CMake lea este archivo es añadir una llamada a add_subdirectory()
en el src/CMakeLists.txt
que apunte a él.
Creamos un nuevo objetivo llamado kirigami-hello-components
y luego lo convertimos en un módulo QML usando ecm_add_qml_module() bajo el nombre de importación org.kde.tutorial.components
y añadimos los archivos QML relevantes.
La llamada a add_library() genera un nuevo objetivo llamado kirigami-hello-components
. Este objetivo tendrá su propio conjunto de archivos de código fuente, archivos QML, enlazará sus propias bibliotecas, etc., aunque necesita estar enlazado al ejecutable, pero una vez que se compila, necesita estar enlazado al ejecutable creado en src/CMakeLists.txt
. Esto se hace añadiendo el nombre del objetivo a la lista de bibliotecas que se enlazarán al ejecutable en target_link_libraries()
.
La llamada a ecm_add_qml_module()
cambia la biblioteca para permitirle aceptar archivos QML como antes, pero esta vez necesitamos usar GENERATE_PLUGIN_SOURCE. Cuando el ejecutable se usa como un destino de respaldo (como con kirigami-hello
) no necesita generar el código del complemento, ya que está integrado en el ejecutable; con módulos QML separados, como kirigami-hello-components
, el código del complemento es necesario.
De manera predeterminada, el qt_add_qml_module() de Qt genera un complemento junto al módulo QML, aunque el ecm_add_qml_module()
de KDE no lo hace de forma predeterminada por compatibilidad con versiones anteriores.
Otro requisito para módulos QML independientes es finalizar el destino. Esto implica principalmente que CMake genera dos archivos: qmldir y qmltypes, que describen los módulos QML que tenemos y exportan sus símbolos para usarlos en la biblioteca. Son importantes durante la instalación de la aplicación para que el ejecutable que se lanza sea capaz de encontrar dónde están los archivos QML para cada módulo, de modo que se puedan añadir automáticamente al destino.
Después podrá instalar el objetivo como antes.
La próxima vez que necesite añadir más archivos QML, recuerde incluirlos en este archivo. Los archivos de C++ que usan la palabra clave QML_ELEMENT, que veremos posteriormente en este tutorial, también se pueden añadir aquí usando target_sources()
. Se puede separar lógicamente el código creando más módulos QML con distintas importaciones, según sea necesario.
Esta configuración será útil para desarrollar la mayoría de las aplicaciones de Kirigami.