Histoire de réussite du transfert ScreenPlay de QMake vers CMake

ScreenPlay est une application open source pour Windows (et bientôt aussi pour Linux et macOS) conçue pour fonctionner avec des fonds d'écran et des widgets. Il a été créé à l'aide d'outils modernes (C ++ / Qt / QML), et y travaille activement depuis le premier semestre 2017. Le code du projet est stocké sur la plateforme GitLab . L'auteur de l'article, dont nous publions aujourd'hui la traduction, développe ScreenPlay. Il a été confronté à un certain nombre de problèmes, qui ont été aidés par la transition de QMake à CMake.











QMake et développement de grands projets



▍Le partage de code dans QMake est très gênant



Lors du développement d'applications assez complexes, il est généralement préférable de les décomposer en petits blocs gérables. Par exemple, si vous souhaitez présenter votre application comme un fichier exécutable principal auquel les bibliothèques sont connectées, alors en utilisant QMake, vous ne pouvez le faire qu'en utilisant un projet basé sur un modèle subdirs. Il s'agit d'un projet, représenté par un fichier, par exemple avec un nom MyApp.pro, qui contient une entrée pour le modèle utilisé et une liste de dossiers de projet:



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


Avec cette approche, nous avons plusieurs sous-projets à notre disposition dans lesquels nous devons organiser le partage de code. Afin d'indiquer au compilateur où exactement dans d'autres projets il doit rechercher les fichiers d'en-tête et les fichiers avec le code source, vous devez fournir à l'éditeur de liens des informations sur les bibliothèques qu'il doit inclure et où trouver les fichiers compilés. QMake le fait en créant d'énormes fichiers .pri qui sont utilisés uniquement pour décrire ce qu'il faut inclure dans le projet. Ceci est similaire à l'utilisation de constructions de vue C ++ normales #include <xyz.h>. En conséquence, il s'avère que, par exemple, le fichier est MyProjectName.priinclus dans la composition MyProjectName.pro. Et pour résoudre le problème du chemin relatif, ajoutez le chemin absolu actuel à chaque ligne.



▍ Dépendances externes



Travailler avec des dépendances externes destinées à différents systèmes d'exploitation se réduit principalement à copier les chemins vers les dépendances correspondantes et à les coller dans un fichier .pro. C'est un travail ennuyeux et fastidieux, car chaque OS a ses propres particularités à cet égard. Par exemple, Linux n'a pas de sous debug- dossiers séparés et release.



▍CONFIG + = ordonné est un tueur de performances de compilation



Un autre inconvénient de QMake est qu'il rencontre parfois des problèmes de compilation. Ainsi, si un projet comporte de nombreux sous-projets, qui sont des bibliothèques utilisées dans d'autres sous-projets, la compilation échoue périodiquement. La raison de l'erreur peut être quelque chose comme ceci: la bibliothèque libAdépend des bibliothèques libBet libC. Mais au moment de l'assemblage, la libAbibliothèque libCn'est pas encore prête. Habituellement, le problème disparaît lorsque le projet est recompilé. Mais le fait que cela se produise indique un problème sérieux avec QMake. Et ces problèmes ne peuvent pas être résolus en utilisant quelque chose commelibA.depends = libB... Probablement (et, peut-être, il en est ainsi), je fais quelque chose de mal, mais ni moi ni mes collègues n'ont réussi à faire face au problème. La seule façon de résoudre le problème avec l'ordre de construction de la bibliothèque est d'utiliser une personnalisation CONFIG += ordered, mais à cause de cela, en raison du manque de constructions parallèles, les performances en souffrent grandement.



QBS et CMake



▍Pourquoi QBS perd-il face à CMake?



Le message concernant la fin du support de QBS (Qt Build System, Qt build system) m'a été un véritable choc. J'ai même été l'un des initiateurs d'une tentative pour changer cela. QBS utilise une belle syntaxe qui est familière à quiconque a déjà écrit du code QML. Je ne peux pas en dire autant de CMake, mais après avoir travaillé avec ce système de construction de projet pendant plusieurs mois, je peux affirmer en toute confiance que passer de QBS à celui-ci était la bonne décision et que je continuerai à utiliser CMake ...



CMake, bien qu'il présente quelques défauts syntaxiques, fonctionne de manière fiable. Et les problèmes de QBS sont plus politiques que techniques.



C'est l'un des principaux facteurs obligeant les programmeurs mécontents de la taille de Qt (à la fois en termes de nombre de lignes de code et en termes de taille de bibliothèque) à chercher une alternative. De plus, de nombreuses personnes n'aiment pas le MOC. Il s'agit d'un compilateur de méta-objets qui convertit le code C ++ écrit à l'aide de Qt en C ++ normal. Grâce à ce compilateur, vous pouvez, par exemple, utiliser des constructions pratiques, telles que celles qui vous permettent de travailler avec des signaux.



▍Alternatives à QBS



En plus de QBS, nous avons à notre disposition des systèmes de construction de projets tels que build2, CMake, Meson, SCons. Ils sont, en dehors de l'écosystème Qt, utilisés dans de nombreux projets.



▍ Mauvaise prise en charge de QBS dans l'IDE



Autant que je sache, le seul IDE qui prend en charge QBS est QtCreator.



▍ Union brillante de vcpkg et CMake



Rappelez-vous comment j'ai ressenti les problèmes avec les dépendances externes ci-dessus? Il n’est donc pas surprenant de voir combien d’ émotions positives le gestionnaire de paquets vcpkg m’a provoquées. Une seule commande suffit pour installer la dépendance! Je pense que vcpkg peut être utile pour tout programmeur C ++.



Syntaxe CMake apparemment peu attrayante



Si vous jugez CMake à partir des dix principaux liens trouvés par Google, il peut sembler que ce système utilise une syntaxe très peu attrayante. Mais le problème ici est que Google est le premier à afficher d'anciens contenus CMake de Stack Overflow, datés de 2008. Des liens vers l'ancienne documentation de la version CMake 2.8 apparaissent également. La syntaxe utilisée lorsque vous travaillez avec CMake peut être assez jolie. Le fait est que l'utilisation de CMake implique principalement l'utilisation des constructions ci-dessous (il s'agit d'une version abrégée du fichier CMakeList.txt du projet ScreenPlay).



#   
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 accélère CMake



Le rôle de CMake est uniquement de générer des instructions pour le système de construction de projet choisi par le développeur. Cela peut être un énorme avantage lorsque vous travaillez avec des personnes qui utilisent Visual Studio plutôt que Qt Creator. Lorsque vous utilisez CMake, vous pouvez (et devriez) choisir Ninja comme système de construction par défaut. Compiler des projets avec le bundle CMake + Ninja est très agréable. Les deux peuvent être trouvés dans la boîte à outils Qt Maintenance. Entre autres, ces outils peuvent gérer les changements très rapidement dans une approche de développement itérative. En fait, tout fonctionne si vite que lorsque j'utilise Godot avec SCons, je veux vraiment utiliser CMake ici aussi.



Vcpkg permet à CMake de briller



La gestion des dépendances dans les projets C ++ n'est pas une tâche facile. Pour le résoudre, de nombreux projets placent même les DLL nécessaires dans leurs référentiels Git. Et c'est mauvais, car cela augmente inutilement la taille des dépôts (nous ne touchons pas à Git LFS ici). Le seul inconvénient de vcpkg est que ce gestionnaire de packages ne prend en charge qu'une seule version globale d'un package (c'est-à-dire que vous devez installer vous-même différentes versions de vcpkg, mais c'est un peu un hack, et cela est rarement nécessaire). Certes, dans les plans de développement du projet, vous pouvez voir qu'il va dans la bonne direction.



Pour installer des packages, utilisez la commande suivante:



vcpkg install crashpad


Tout en travaillant sur ScreenPlay, nous avons simplement créé les scripts install_dependencies_windows.bat et install_dependencies_linux_mac.sh pour cloner le référentiel vcpkg, le construire et installer toutes nos dépendances. Lorsque vous travaillez avec Qt Creator, vous devez écrire dans le CMAKE_TOOLCHAIN_FILEchemin relatif de vcpkg. De plus, vcpkg doit savoir quel système d'exploitation et quelle architecture nous utilisons.



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


Avez-vous besoin d'installer une autre bibliothèque? Il suffit d'utiliser la commande type vcpkg install myLibToInstall.



Résultat



L'approche consistant à utiliser les plus récents et les plus populaires a ses avantages. Mais que faire, par exemple, lorsque des systèmes de construction à fort potentiel comme QBS se retrouvent soudainement sur la touche? En fin de compte, le développeur décide lui-même de ce qu'il doit utiliser dans ses projets. C'est pourquoi j'ai décidé de transférer mon projet chez CMake. Et, je dois dire que c'était la bonne décision. Aujourd'hui, en 2020, CMake a l'air plutôt bien.



Utilisez-vous CMake et vcpkg?










All Articles