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.pri
inclus 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
libA
dépend des bibliothèques libB
et libC
. Mais au moment de l'assemblage, la libA
bibliothèque libC
n'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_FILE
chemin 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?