Skip to main content
Ir para o conteúdo

Compreendendo o CMakeLists

Entendendo como os arquivos CMakeLists.txt funcionam

CMake

Em nosso tutorial introdutório, usamos o CMake como sistema de compilação para nossa aplicação, mas só prestamos realmente atenção a um dos nossos arquivos CMakeLists.txt. Aqui, vamos explicar como ele funciona com mais detalhes.

O CMake é útil porque nos permite automatizar muitas das coisas que precisam ser feitas antes da compilação.

O CMakeLists.txt raiz

Você deve se lembrar deste arquivo CMakeLists.txt do primeiro tutorial:

 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)

A primeira linha, cmake_minimum_required(), define a versão do CMake que chamaremos.

Depois disso, project(kirigami-tutorial) define o nome do projeto.

Em seguida, chegamos a uma seção onde incluímos uma série de configurações necessárias do CMake e do KDE usando extra-cmake-modules. Eles fornecem um conjunto de utilitários úteis:

  • KDEInstallDirs fornece variáveis ​​de conveniência como ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}, ${KDE_INSTALL_QMLDIR}, ${KDE_INSTALL_BINDIR} e ${KDE_INSTALL_LIBDIR}.
  • KDECMakeSettings fornece recursos como CMAKE_AUTORCC ON, um destino de uninstall que pode ser usado com cmake --build build/ --target uninstall e ENABLE_CLAZY.
  • KDECompilerSettings fornece um padrão C++ mínimo, sinalizadores de compilador como -pedantic e macros de melhores práticas como -DQT_NO_CAST_FROM_ASCII para exigir conversões explícitas como QStringLiteral().
  • ECMFindQmlModule fornece uma maneira de garantir que uma dependência QML de tempo de execução seja encontrada em tempo de compilação.
  • ECMQmlModule fornece comandos do CMake como ecm_add_qml_module() e ecm_target_qml_sources().

A seção a seguir é importante porque especifica quais dependências serão incluídas em tempo de compilação. Vejamos a primeira:

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() encontra e carrega a biblioteca externa e seus componentes.
  • REQUIRED informa ao CMake para sair com um erro se o pacote não puder ser encontrado.
  • COMPONENTS é um parâmetro que precede os componentes específicos do framework que incluiremos.
  • Cada palavra depois de COMPONENTS se refere a um componente específico da biblioteca.

A linha de instalação instrui o CMake a instalar o arquivo desktop em ${KDE_INSTALL_APPDIR}, que no Linux é traduzido para $XDG_DATA_DIRS/applications, geralmente /usr/share/applications, e no Windows é traduzido para C:/Arquivos de Programas/${NOME_PROJETO}/bin/data/applications:

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

A linha final permite que o CMake exiba quais pacotes encontrou e faz com que a compilação falhe imediatamente se encontrar um erro:

36
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)

E acima disso, add_subdirectory(src) aponta o CMake para a pasta src/, onde ele encontra outro arquivo 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})

Enquanto o primeiro arquivo tratava de metadados e buscava bibliotecas, este consistirá em lidar com dependências e instalar o aplicativo. Ele contém as seguintes chamadas CMake:

  • add_executable() cria o executável que usaremos para executar nosso projeto.
  • ecm_add_qml_module() cria um destino de módulo QML que será acessível por meio da importação "org.kde.tutorial".
  • target_sources() adiciona arquivos de origem C++ ao destino executável.
  • ecm_target_qml_sources() adiciona arquivos QML ao módulo.
  • target_link_libraries() vincula as bibliotecas C++ usadas em nosso código ao nosso executável. Kirigami não está incluído aqui porque estamos usando apenas seu módulo QML.
  • install() instala o executável no sistema.

A documentação para os dois comandos ECM pode ser encontrada na API do extra-cmake-modules para ECMQmlModule.

A chamada para ecm_add_qml_module() foi usada aqui para modificar o executável de código-fonte C++ tradicional e transformá-lo em algo que possa aceitar arquivos QML e código-fonte C++ acessível a partir de QML, no que é chamado de usando o executável como destino de suporte para um módulo QML. Isso significa que os arquivos QML são executados diretamente como parte do aplicativo, o que geralmente acontece com aplicativos.

Você também pode criar um módulo QML separado que não use o executável como destino de apoio usando ecm_add_qml_module(). Nesse caso, você criaria um destino de biblioteca usando add_library(), vincularia-o a um destino executável existente usando target_link_libraries() e, além de instalar a biblioteca com install(), você precisará finalizar o módulo QML com ecm_finalize_qml_module() para que ele possa gerar dois arquivos: qmldir e qmltypes. Esses arquivos são usados ​​por aplicativos QtQuick para encontrar módulos QML separados.

O método para criar um módulo QML separado é melhor exemplificado em Usando arquivos separados.

Estas são adições fornecidas por extra-cmake-modules para facilitar o uso do registro declarativo do Qt (a substituição dos arquivos de recursos do Qt).

A documentação para todos os três comandos pode ser encontrada na API do extra-cmake-modules para ECMQmlModule.

src/components/CMakeLists.txt

No tutorial sobre como dividir seu código em arquivos separados, um novo arquivo CMake foi introduzido para permitir módulos QML separados:

 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})

O requisito para que este arquivo seja lido pelo CMake é adicionar uma chamada para add_subdirectory() no src/CMakeLists.txt apontando para ele.

Criamos um novo alvo chamado kirigami-hello-components e o transformamos em um módulo QML usando ecm_add_qml_module() com o nome de importação org.kde.tutorial.components e adicionamos os arquivos QML relevantes.

A chamada para add_library() gera um novo alvo chamado kirigami-hello-components. Este alvo terá seu próprio conjunto de arquivos de código-fonte, arquivos QML, vinculará suas próprias bibliotecas e assim por diante, mas precisa ser vinculado ao executável. Uma vez compilado, ele precisa ser vinculado ao executável criado em src/CMakeLists.txt. Isso é feito adicionando o nome do alvo à lista de bibliotecas que serão vinculadas ao executável em target_link_libraries().

A chamada para ecm_add_qml_module() altera a biblioteca para permitir que ela aceite arquivos QML como antes, mas desta vez precisamos usar GENERATE_PLUGIN_SOURCE. Quando o executável é usado como um alvo de apoio (como com kirigami-hello), ele não precisa gerar código de plugin, pois ele está embutido no executável; com módulos QML separados, como kirigami-hello-components, o código de plugin é necessário.

O qt_add_qml_module() do Qt upstream gera, por padrão, um plugin junto com o módulo QML, mas o ecm_add_qml_module() do KDE, por padrão, não o faz para compatibilidade com versões anteriores.

Outra coisa necessária para módulos QML separados é finalizar o alvo. Isso significa principalmente que o CMake gera dois arquivos, qmldir e qmltypes, que descrevem os módulos QML que temos e exportam seus símbolos para uso na biblioteca. Eles são importantes ao instalar seu aplicativo para que o executável em execução seja capaz de encontrar onde estão os arquivos QML de cada módulo, para que eles sejam adicionados automaticamente ao alvo.

Você pode então instalar o alvo como antes.

Da próxima vez que precisar adicionar mais arquivos QML, lembre-se de incluí-los neste arquivo. Arquivos C++ que usam a palavra-chave QML_ELEMENT, que veremos mais adiante neste tutorial, também podem ser adicionados aqui usando target_sources(). Você pode separar logicamente seu código criando mais módulos QML com importações diferentes, conforme necessário.

Esta configuração será útil ao desenvolver a maioria dos aplicativos Kirigami.