ScreenPlay从QMake转移到CMake的成功故事

ScreenPlay是Windows的开源应用程序(不久之后还将用于Linux和macOS),旨在与墙纸和小部件一起使用。它是使用现代工具(C ++ / Qt / QML)创建的,自2017年上半年以来一直在积极地进行开发。项目代码存储在GitLab平台上 这篇文章的作者(我们今天将其翻译发表)正在开发ScreenPlay。从QMake到CMake的过渡,他遇到了许多问题。











QMake和大型项目开发



QQMake中的代码共享非常不方便



在开发相当复杂的应用程序时,通常最好将它们分解为可管理的小块。例如,如果您需要将应用程序显示为与库连接的主要可执行文件,则可以使用QMake,这只能通过基于模板项目来完成subdirs。这是一个项目,由一个名为name的文件表示MyApp.pro,其中包含所用模板的条目和项目文件夹列表:



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


使用这种方法,我们可以使用几个子项目来组织代码共享。为了告诉编译器在其他项目中确切需要在哪里查找头文件和带有源代码的文件,您需要告诉链接程序有关它需要包括哪些库以及在哪里寻找编译文件的信息。QMake通过创建巨大的.pri文件来做到这一点,这些文件仅用于描述要包含在项目中的内容。这类似于使用常规C ++视图构造#include <xyz.h>结果,事实证明,例如,文件MyProjectName.pri包含在composition中MyProjectName.pro为了解决相对路径问题,请将当前的绝对路径添加到每行。



ternal外部依赖



使用针对各种操作系统的外部依赖项的方法主要减少为将路径复制到相应的依赖项并将其粘贴到.pro文件中。这是一个枯燥而乏味的工作,因为每个OS在这方面都有其自身的特点。例如,Linux没有单独的子文件夹debugrelease



FIGCONFIG + =命令是编译性能的杀手er



QMake的另一个缺点是它具有间歇性的编译问题。因此,如果项目中有许多子项目,这些子项目是其他子项目中使用的库,则编译会定期失败。错误的原因可能是这样的:库libA取决于库libBlibC。但是到组装时,该libAlibC尚未准备就绪。通常,重新编译项目后问题就消失了。但是,这完全发生的事实表明QMake存在严重问题。这些问题无法通过使用以下方法解决libA.depends = libB... 可能(也许是这样),我做错了事,但是我和我的同事都没有设法解决这个问题。解决库的构建顺序问题的唯一方法是使用自定义CONFIG += ordered,但是由于这个原因,通过消除并行构建,性能会受到很大影响。



QBS和CMake



BS为什么QBS输给CMake?



该消息有关的QBS(Qt的构建系统,Qt的构建系统)支持结束之际,一个真正的冲击给我。我什至是尝试改变这一状况的发起者之一。 QBS使用很好的语法,任何编写过QML代码的人都熟悉。关于CMake,我不能说同样的话,但是在使用该项目构建系统几个月后,我可以自信地说,从QBS切换到它是正确的决定,并且我将继续使用CMake。 ...



CMake尽管存在一些语法缺陷,但可以可靠地运行。 QBS的问题比技术问题更具政治性。



这是迫使对Qt大小不满意的程序员(就代码行数和库的大小而言)不满意的主要因素之一。此外,许多人强烈不喜欢MOC。它是一个元对象编译器,可将使用Qt编写的C ++代码转换为常规C ++。例如,借助此编译器,您可以使用方便的构造,例如允许您处理信号的构造。



QQBS的替代品



除了QBS,我们还可以使用诸如build2,CMake,Meson,SCons之类的项目构建系统。它们在Qt生态系统以外的许多项目中使用。



IDE IDE中对QBS的支持不佳



据我所知,唯一支持QBS的IDE是QtCreator。



v vcpkg和CMake的精妙结合



还记得我对上面的外部依赖关系的问题感到愤慨吗?因此,vcpkg软件包管理器给我带来了多少积极的情绪也就不足为奇了一个命令足以安装依赖项!我认为vcpkg对任何C ++程序员都有用。



貌似没有吸引力的CMake语法



如果从Google找到的前十个链接中判断CMake,则该系统似乎使用的语法不太吸引人。但是这里的问题在于,Google是第一个显示Stack Overflow于2008年发布的旧CMake内容的人。也指向CMake 2.8版本的旧文档的链接。使用CMake时使用的语法可能非常漂亮。事实是,使用CMake主要涉及使用以下所示的结构(这是ScreenPlay项目中CMakeList.txt文件的缩写版本)。



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


忍者加快CMake



CMake的作用只是为开发人员选择的项目构建系统生成指令。与使用Visual Studio而不是Qt Creator的人一起工作时,这可能是一个巨大的优势。使用CMake时,您可以(并且应该)选择Ninja作为默认的构建系统。使用CMake + Ninja捆绑包编译项目非常好。两者都可以在Qt维护工具箱中找到。这些工具除其他外,可以通过迭代开发方法非常快速地处理更改。实际上,一切工作都如此之快,以至于将Godot与SCons一起使用时,我真的也想在这里使用CMake。



Vcpkg使CMake发光



在C ++项目中管理依赖项并非易事。为了解决这个问题,许多项目甚至在其Git存储库中放置了必要的DLL。这很不好,因为这不必要地增加了存储库的大小(我们在这里不涉及Git LFS)。 vcpkg的唯一缺点是此程序包管理器仅支持程序包的一个全局版本(也就是说,您必须自己安装不同版本的vcpkg,但这有点麻烦,很少需要这样做)。诚然,在计划用于该项目的开发,你可以看到它是在正确的方向前进。



要安装软件包,请使用以下命令:



vcpkg install crashpad


在使用ScreenPlay时,我们仅创建了install_dependencies_windows.batinstall_dependencies_linux_mac.sh脚本来克隆vcpkg存储库,构建它并安装所有依赖项。使用Qt Creator时,您需要写入CMAKE_TOOLCHAIN_FILEvcpkg相对路径。此外,需要告知vcpkg我们正在使用什么操作系统和什么体系结构。



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


您是否需要安装其他任何库?为此,只需使用form的命令vcpkg install myLibToInstall



结果



使用最新最流行的方法有其优势。但是,例如,当构建具有巨大潜力的系统(例如QBS)突然陷入困境时该怎么办?最终,开发人员自己决定在项目中使用什么。这就是为什么我决定将我的项目转移到CMake的原因。而且,我必须说,这是正确的决定。今天,在2020年,CMake看起来还不错。



您正在使用CMake和vcpkg吗?










All Articles