Förstå CMakeLists

Att begripa hur CMakeLists.txt-filer fungerar

CMake

I vår inledande handledning, använde vi CMake som byggsystem för vårt program, men vi har egentligen bara uppmärksammat en av våra CMakeLists.txt. Här går vi igenom hur det fungerar lite mer detaljerat.

CMake är användbart eftersom det låter oss automatisera mycket av grejorna som måste göras innan kompilering.

CMakeLists.txt i rotkatalogen

Du kanske kommer ihåg filen CMakeLists.txt från den första handledningen:

 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)

Första raden, cmake_minimum_required() ställer in version av CMake som vi anropar.

Därefter definierar project(kirigami-tutorial) projektets namn.

Därefter kommer vi till en sektion där vi inkluderar ett antal nödvändiga CMake- och KDE-inställningar genom att använda extra-cmake-modules. De tillhandahåller en uppsättning användbara verktyg.

  • KDEInstallDirs tillhandahåller bekvämlighetsvariabler såsom ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}, ${KDE_INSTALL_QMLDIR}, ${KDE_INSTALL_BINDIR} and ${KDE_INSTALL_LIBDIR}.
  • KDECMakeSettings tillhandahåller saker som CMAKE_AUTORCC ON, målet avinstallera som kan användas med cmake --build build/ - -target uninstall och ENABLE_CLAZY.
  • KDECompilerSettings tillhandahåller den minimala C++ standarden, kompilatorflaggor som "-pedantic" och makron för bästa praxis som "-DQT_NO_CAST_FROM_ASCII" för att kräva explicita konverteringar som QStringLiteral().
  • ECMFindQmlModule tillhandahåller ett sätt att säkerställa att ett QML-beroende vid körtid hittas vid kompilering.
  • ECMQmlModule tillhandahåller CMake-kommandon som ecm_add_qml_module() och ecm_target_qml_sources().

Den följande sektionen är viktig, eftersom den anger vilka beroenden vi tar med vid kompileringstillfället. Låt oss titta på den första:

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() hittar och läser in det externa biblioteket och dess komponenter.
  • REQUIRED talar om för CMake att avsluta med ett fel om paketet inte kan hittas.
  • COMPONENTS är en parameter som föregår de specifika komponenterna för ramverket vi inkluderar.
  • Varje ord efter COMPONENTS refererar till en specifik komponent i biblioteket.

Installationsraden instruerar CMake att installera skrivbordsfilen i ${KDE_INSTALL_APPDIR}, som på Linux översätts till $XDG_DATA_DIRS/applications, vanligtvis /usr/share/applications, och på Windows översätts till C:/Program Filer/${PROJECT_NAME}/bin/data/applications:

32
add_subdirectory(src)

Den sista raden låter CMake skriva ut vilka paket som har hittats, och gör att kompileringen misslyckas omedelbart om den stöter på ett fel:

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

Och ovanför den pekar add_subdirectory(src) CMake på katalogen 'src/', där det finns en annan CMakeLists.txt fil.

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

Medan den första filen hanterade metadata och hittade bibliotek, kommer denna att bestå av att hantera beroenden och installera programmet. Den har följande CMake-anrop:

  • add_executable() skapar det körbara programmet vi använder för att köra vårt projekt.
  • ecm_add_qml_module() skapar ett mål för QML-modulen som är tillgängligt via import av "org.kde.tutorial".
  • target_sources() lägger till C++ källkodsfiler i det körbara målet.
  • ecm_target_qml_sources() lägger till QML-filer i modulen.
  • target_link_libraries() länkar C++ biblioteken som används i vår kod till vårt körbara program. Kirigami inkluderas inte här eftersom vi bara använder dess QML-modul.
  • install() installerar det körbara programmet på systemet.

Dokumentationen för de två ECM-kommandona finns i extra-cmake-modules programmeringsgränssnitt för ECMQmlModule.

Anropet till ecm_add_qml_module() användes här för att modifiera det traditionella körbara målet för C++ källkoden och omvandla det till något som kan acceptera QML-filer och C++ källkod som är åtkomlig från QML i vad som kallas med den körbara filen som stödmål för en QML-modul. Det innebär att QML-filerna körs direkt som en del av programmet, vilket ofta är fallet för program.

Man kan också skapa en separat QML-modul som inte använder den körbara filen som stödmål med hjälp av ecm_add_qml_module(). I det här fallet skulle man skapa ett biblioteksmål med add_library(), länka det till ett befintligt körbart mål med target_link_libraries( ), och förutom att installera biblioteket med install() också slutföra QML-modulen med ecm_finalize_qml_module() så den kan generera två filer: qmldir och qmltypes. Filerna används av QtQuick-programmet för att hitta separata QML-moduler.

Metoden för att skapa en separat QML-modul exemplifieras bättre i Använda separata filer.

De är tillägg som tillhandahålls av extra-cmake-modules för att göra användning av Qt deklarativ registrering (ersättning av Qt:s resursfiler) enklare.

Dokumentationen för alla tre kommandon finns i extra-cmake-modules programmeringsgränssnitt för ECMQmlModule.

src/components/CMakeLists.txt

I handledningen om hur man delar upp sin kod i separata filer, introducerades en ny CMake-fil för att möjliggöra separata QML-moduler:

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

Kravet för att filen ska läsas av CMake är att lägga till ett anrop till add_subdirectory() i src/CMakeLists.txt som pekar på den.

Vi skapar ett nytt mål som heter kirigami-hello-components och gör det sedan till en QML-modul med hjälp av ecm_add_qml_module() under importnamnet org.kde.tutorial.components och lägger till relevanta QML-filer.

Anropet till add_library() genererar ett nytt mål som heter kirigami-hello-components. Målet har sin egen uppsättning källkodsfiler, QML-filer, länkar sina egna bibliotek och så vidare, men det måste länkas till den körbara filen som skapades i src/CMakeLists.txt när det väl har kompilerats. Det görs genom att lägga till målnamnet i listan över bibliotek som ska länkas till den körbara filen i target_link_libraries().

Anropet till ecm_add_qml_module() ändrar biblioteket så att det kan acceptera QML-filer som tidigare, men den här gången måste vi använda GENERATE_PLUGIN_SOURCE . När den körbara filen används som ett stödmål (som med kirigami-hello) behöver den inte generera insticksprogramkod eftersom det är inbyggt i den körbara filen; med separata QML-moduler som "kirigami-hello-components" är insticksprogramkoden nödvändig.

Uppströms genererar Qt qt_add_qml_module() standardmässigt ett insticksprogram tillsammans med QML-modulen, men KDE:s ecm_add_qml_module() är inte standard för bakåtkompatibilitet.

En annan sak som är nödvändig för separata QML-moduler är att slutföra målet. Det innebär huvudsakligen att CMake genererar två filer, qmldir och qmltypes, som beskriver QML-modulerna vi har och exporterar deras symboler för användning i biblioteket. De är viktiga när programmet installeras så att den körbara filen som körs kan hitta var QML-filerna för varje modul finns, så att de automatiskt läggs till i målet.

Därefter kan du bara installera målet som tidigare.

Nästa gång du behöver lägga till fler QML-filer, kom ihåg att inkludera dem i den här filen. C++ filer som använder nyckelordet QML_ELEMENT som vi kommer att se mycket senare i handledningen kan också läggas till här med target_sources( ). Man kan separera sin kod logiskt genom att skapa fler QML-moduler med olika importer efter behov.

Inställningen är användbar när vi utvecklar de flesta program i Kirigami.