Erfolgsgeschichte der Übertragung von ScreenPlay von QMake auf CMake

ScreenPlay ist eine Open Source-Anwendung für Windows (und bald auch für Linux und MacOS), die für die Verwendung mit Hintergrundbildern und Widgets entwickelt wurde. Es wurde mit modernen Tools (C ++ / Qt / QML) erstellt und arbeitet seit dem ersten Halbjahr 2017 aktiv daran. Der Projektcode wird auf der GitLab- Plattform gespeichert . Der Autor des Artikels, dessen Übersetzung wir heute veröffentlichen, entwickelt ScreenPlay. Er hatte mit einer Reihe von Problemen zu kämpfen, die durch den Übergang von QMake zu CMake behoben wurden.











QMake und Großprojektentwicklung



▍Code-Sharing in QMake ist sehr unpraktisch



Bei der Entwicklung ziemlich komplexer Anwendungen ist es normalerweise am besten, sie in kleine, überschaubare Teile zu zerlegen. Wenn Sie beispielsweise Ihre Anwendung als ausführbare Hauptdatei präsentieren müssen, mit der Bibliotheken verbunden sind, können Sie mit QMake nur ein Projekt verwenden, das auf einer Vorlage basiert subdirs. Dies ist ein Projekt, das durch eine Datei dargestellt wird, beispielsweise mit einem Namen MyApp.pro, die einen Eintrag für die verwendete Vorlage und eine Liste der Projektordner enthält:



  TEMPLATE = subdirs
 
  SUBDIRS = \
            src/app \   #  
            src/lib \
            src/lib2


Mit diesem Ansatz stehen uns mehrere Teilprojekte zur Verfügung, in denen wir die gemeinsame Nutzung von Code organisieren müssen. Um den Compiler darüber zu informieren, wo genau in anderen Projekten nach Header-Dateien und Dateien mit Quellcode gesucht werden muss, müssen Sie dem Linker mitteilen, welche Bibliotheken er enthalten muss und wo nach kompilierten Dateien gesucht werden muss. QMake erstellt dazu riesige PRI-Dateien, die ausschließlich dazu dienen, zu beschreiben, was in das Projekt aufgenommen werden soll. Dies ähnelt der Verwendung regulärer C ++ - Ansichtskonstrukte #include <xyz.h>. Als Ergebnis stellt sich heraus, dass beispielsweise die Datei MyProjectName.priin der Komposition enthalten ist MyProjectName.pro. Um das relative Pfadproblem zu beheben, fügen Sie jeder Zeile den aktuellen absoluten Pfad hinzu.



▍Externe Abhängigkeiten



Das Arbeiten mit externen Abhängigkeiten, die für verschiedene Betriebssysteme vorgesehen sind, beschränkt sich hauptsächlich darauf, die Pfade in die entsprechenden Abhängigkeiten zu kopieren und in eine .pro-Datei einzufügen. Dies ist eine langweilige und mühsame Aufgabe, da jedes Betriebssystem diesbezüglich seine eigenen Besonderheiten aufweist. Zum Beispiel hat Linux keine separaten Unterordner debugund release.



▍CONFIG + = bestellt ist ein Killer für die Kompilierungsleistung



Ein weiterer Nachteil von QMake ist, dass es zeitweise Kompilierungsprobleme gibt. Wenn das Projekt also viele Teilprojekte enthält, bei denen es sich um Bibliotheken handelt, die in anderen Teilprojekten verwendet werden, schlägt die Kompilierung regelmäßig fehl. Der Grund für den Fehler kann etwa so sein: Die Bibliothek libAhängt von den Bibliotheken libBund ab libC. Zum Zeitpunkt der Montage ist die libABibliothek libCjedoch noch nicht fertig. Normalerweise verschwindet das Problem, wenn das Projekt neu kompiliert wird. Die Tatsache, dass dies überhaupt geschieht, weist jedoch auf ein ernstes Problem mit QMake hin. Und diese Probleme können nicht mit so etwas gelöst werdenlibA.depends = libB... Wahrscheinlich (und vielleicht ist es so) mache ich etwas falsch, aber weder ich noch meine Kollegen haben es geschafft, mit dem Problem fertig zu werden. Die einzige Möglichkeit, das Problem mit der Reihenfolge der Bibliothekserstellung zu lösen, besteht in der Verwendung einer Anpassung CONFIG += ordered. Aus diesem Grund leidet die Leistung aufgrund des Fehlens paralleler Erstellungen erheblich.



QBS und CMake



▍Warum verliert QBS gegen CMake?



Die Nachricht über das Ende der Unterstützung für QBS (Qt Build System, Qt Build System) war für mich ein echter Schock. Ich war sogar einer der Initiatoren eines Versuchs, dies zu ändern. QBS verwendet eine nette Syntax, die jedem bekannt ist, der jemals QML-Code geschrieben hat. Ich kann nicht dasselbe über CMake sagen, aber nachdem ich einige Monate mit diesem Projekt-Build-System gearbeitet habe, kann ich zuversichtlich sagen, dass der Wechsel von QBS zu ihm die richtige Entscheidung war und dass ich CMake weiterhin verwenden werde ...



Obwohl CMake einige syntaktische Mängel aufweist, funktioniert es zuverlässig. Und die Probleme von QBS sind eher politischer als technischer Natur.



Dies ist einer der Hauptfaktoren, die Programmierer, die mit der Größe von Qt (sowohl hinsichtlich der Anzahl der Codezeilen als auch hinsichtlich der Bibliotheksgröße) unzufrieden sind, dazu zwingen, nach einer Alternative zu suchen. Darüber hinaus mögen viele Menschen MOC nicht. Es ist ein Metaobjekt-Compiler, der mit Qt geschriebenen C ++ - Code in reguläres C ++ konvertiert. Dank dieses Compilers können Sie beispielsweise praktische Konstrukte verwenden, z. B. solche, mit denen Sie mit Signalen arbeiten können.



▍Alternativen zu QBS



Zusätzlich zu QBS verfügen wir über Projektbuild-Systeme wie build2, CMake, Meson, SCons. Sie werden außerhalb des Qt-Ökosystems in vielen Projekten eingesetzt.



▍ Schlechte QBS-Unterstützung in IDE



Soweit ich weiß, ist QtCreator die einzige IDE, die QBS unterstützt.



▍ Brillante Vereinigung von vcpkg und CMake



Erinnern Sie sich, wie ich die oben genannten Probleme mit externen Abhängigkeiten verärgert habe? Es ist also nicht verwunderlich, wie viele positive Emotionen mir der vcpkg-Paketmanager gegeben hat. Ein Befehl reicht aus, um die Abhängigkeit zu installieren! Ich denke, vcpkg kann für jeden C ++ - Programmierer nützlich sein.



Scheinbar unattraktive CMake-Syntax



Wenn Sie CMake anhand der zehn von Google gefundenen Top-Links beurteilen, scheint das System eine sehr unattraktive Syntax zu verwenden. Das Problem hierbei ist jedoch, dass Google als erstes Unternehmen altes CMake-Material von Stack Overflow aus dem Jahr 2008 anzeigt. Es werden auch Links zur alten Dokumentation für die CMake 2.8-Version angezeigt. Die Syntax, die bei der Arbeit mit CMake verwendet wird, kann ziemlich hübsch sein. Tatsache ist, dass die Verwendung von CMake hauptsächlich die Verwendung der unten gezeigten Konstruktionen umfasst (dies ist eine verkürzte Version der Datei CMakeList.txt aus dem ScreenPlay-Projekt).



#   
cmake_minimum_required(VERSION 3.16.0)

#   .       
#       ${PROJECT_NAME}
project(ScreenPlay)

#   Qt,    MOC
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON)

#  -   .    src,
#   .       add_executable
set(src main.cpp
        app.cpp
        #  - 
        src/util.cpp
        src/create.cpp)

set(headers app.h
        src/globalvariables.h
        #   - 
        src/util.h
        src/create.h)

#  Qt     
qt5_add_big_resources(resources  resources.qrc)

#  CMake  qml  C++   release
#   !
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set(qml qml.qrc)
else()
    qtquick_compiler_add_resources(qml qml.qrc )
endif()

#  CMake   .  ,   ,  CMAKE_TOOLCHAIN_FILE
#         !
find_package(
  Qt5
  COMPONENTS Quick
             QuickCompiler
             Widgets
             Gui
             WebEngine
  REQUIRED)

#   vcpkg
find_package(ZLIB REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(libzippp CONFIG REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)

#  CMake    : 
# add_executable    
# add_library   
add_executable(${PROJECT_NAME} ${src} ${headers} ${resources} ${qml})

#        Windows
# https://stackoverflow.com/questions/8249028/how-do-i-keep-my-qt-c-program-from-opening-a-console-in-windows
set_property(TARGET ${PROJECT_NAME} PROPERTY WIN32_EXECUTABLE true)

#     .    
#     vcpkg.      
# dll/lib/so/dynlib  vcpkg/installed
#      , 
#   project(MyLib)  target_link_libraries.
#        .
target_link_libraries(${PROJECT_NAME}
    PRIVATE
    Qt5::Quick
    Qt5::Gui
    Qt5::Widgets
    Qt5::Core
    Qt5::WebEngine
    nlohmann_json::nlohmann_json
    libzippp::libzippp
    ScreenPlaySDK
    QTBreakpadplugin)

#  CMake      build   ,   .
# ${CMAKE_BINARY_DIR} -   build!
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/bin/assets/fonts)
configure_file(assets/fonts/NotoSansCJKkr-Regular.otf ${CMAKE_BINARY_DIR}/bin/assets/fonts COPYONLY)


Ninja beschleunigt CMake



Die Rolle von CMake besteht nur darin, Anweisungen für das vom Entwickler ausgewählte Projekterstellungssystem zu generieren. Dies kann ein großes Plus sein, wenn Sie mit Personen arbeiten, die Visual Studio anstelle von Qt Creator verwenden. Wenn Sie CMake verwenden, können (und sollten) Sie Ninja als Standard-Build-System auswählen . Das Kompilieren von Projekten mit dem CMake + Ninja-Bundle ist sehr schön. Beide finden Sie in der Qt Maintenance Toolbox. Unter anderem können diese Tools Änderungen in einem iterativen Entwicklungsansatz sehr schnell verarbeiten. Tatsächlich funktioniert alles so schnell, dass ich bei der Verwendung von Godot mit SCons auch hier wirklich CMake verwenden möchte.



Mit Vcpkg kann CMake glänzen



Das Verwalten von Abhängigkeiten in C ++ - Projekten ist keine leichte Aufgabe. Um dies zu lösen, platzieren viele Projekte sogar die erforderlichen DLLs in ihren Git-Repositorys. Und das ist schlecht, da dies die Größe der Repositorys unnötig erhöht (wir berühren Git LFS hier nicht). Der einzige Nachteil von vcpkg ist, dass dieser Paketmanager nur eine globale Version eines Pakets unterstützt (das heißt, Sie müssen verschiedene Versionen von vcpkg selbst installieren, dies ist jedoch ein kleiner Hack, und dies wird selten benötigt). In den Entwicklungsplänen des Projekts können Sie zwar sehen, dass es in die richtige Richtung geht.



Der folgende Befehl wird zum Installieren von Paketen verwendet:



vcpkg install crashpad


Während der Arbeit an ScreenPlay haben wir einfach die Skripte install_dependencies_windows.bat und install_dependencies_linux_mac.sh erstellt , um das vcpkg-Repository zu klonen, zu erstellen und alle unsere Abhängigkeiten zu installieren. Wenn Sie mit Qt Creator arbeiten, müssen Sie in den CMAKE_TOOLCHAIN_FILErelativen Pfad zu vcpkg schreiben. Außerdem muss vcpkg mitgeteilt werden, welches Betriebssystem und welche Architektur wir verwenden.



    #  QtCreator. Extras -> Tools -> Kits ->  -> CMake Configuration.    :
    CMAKE_TOOLCHAIN_FILE:STRING=%{CurrentProject:Path}/Common/vcpkg/scripts/buildsystems/vcpkg.CMake
    VCPKG_TARGET_TRIPLET:STRING=x64-windows


Müssen Sie eine andere Bibliothek installieren? Verwenden Sie dazu einfach den Befehl des Formulars vcpkg install myLibToInstall.



Ergebnis



Der Ansatz, das Neueste und Beliebteste zu verwenden, hat seine Vorteile. Aber was tun, wenn beispielsweise Build-Systeme mit großem Potenzial wie QBS plötzlich am Rande stehen? Letztendlich entscheidet der Entwickler selbst, was er in seinen Projekten verwendet. Deshalb habe ich beschlossen, mein Projekt auf CMake zu übertragen. Und ich muss sagen, es war die richtige Entscheidung. Heute, im Jahr 2020, sieht CMake ziemlich gut aus.



Verwenden Sie CMake und vcpkg?










All Articles