Kisah sukses transfer ScreenPlay dari QMake ke CMake

ScreenPlay adalah aplikasi open source untuk Windows (dan segera juga untuk Linux dan macOS) yang dirancang untuk bekerja dengan wallpaper dan widget. Itu dibuat menggunakan alat modern (C ++ / Qt / QML), dan telah aktif mengerjakannya sejak paruh pertama tahun 2017. Kode proyek disimpan di platform GitLab . Penulis artikel, terjemahan yang kami terbitkan hari ini, sedang mengembangkan ScreenPlay. Ia menghadapi sejumlah masalah, yang terbantu oleh transisi dari QMake ke CMake.











QMake dan pengembangan proyek besar



▍ Berbagi kode di QMake sangat merepotkan



Saat mengembangkan aplikasi yang cukup kompleks, biasanya yang terbaik adalah memecahnya menjadi beberapa bagian kecil yang dapat dikelola. Misalnya, jika Anda perlu menampilkan aplikasi Anda sebagai file eksekusi utama yang perpustakaan terhubung, kemudian menggunakan QMake, ini dapat dilakukan hanya dengan menggunakan proyek berdasarkan template subdirs. Ini adalah proyek, diwakili oleh file, katakanlah dengan nama MyApp.pro, yang berisi entri untuk templat yang digunakan dan daftar folder proyek:



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


Dengan pendekatan ini, kami memiliki beberapa subproyek yang kami miliki di mana kami perlu mengatur pembagian kode. Untuk memberi tahu compiler tentang di mana tepatnya dalam proyek lain ia perlu mencari file header dan file dengan kode sumber, Anda perlu memberi tahu informasi linker tentang library mana yang perlu disertakan dan di mana mencari file yang dikompilasi. QMake melakukan ini dengan membuat file .pri besar yang digunakan semata-mata untuk menjelaskan apa yang harus disertakan dalam proyek. Ini mirip dengan menggunakan konstruksi tampilan C ++ biasa #include <xyz.h>. Alhasil, ternyata, misalnya, file tersebut MyProjectName.primasuk dalam komposisi MyProjectName.pro. Dan untuk memperbaiki masalah jalur relatif, tambahkan jalur absolut saat ini ke setiap baris.



▍ Dependensi eksternal



Bekerja dengan dependensi eksternal yang ditujukan untuk berbagai sistem operasi pada dasarnya dikurangi dengan menyalin jalur ke dependensi yang sesuai dan menempelkannya ke file .pro. Ini adalah pekerjaan yang membosankan dan membosankan, karena setiap OS memiliki kekhasan tersendiri dalam hal ini. Misalnya, Linux tidak memiliki subfolder terpisah debugdan release.



▍CONFIG + = memerintahkan adalah pembunuh kinerja kompilasi



Kelemahan lain dari QMake adalah ia memiliki masalah kompilasi yang terputus-putus. Jadi, jika proyek memiliki banyak subproyek, yang merupakan pustaka yang digunakan dalam subproyek lain, maka kompilasi gagal secara berkala. Alasan kesalahannya mungkin seperti ini: perpustakaan libAbergantung pada perpustakaan libBdan libC. Namun pada saat perakitan, libAperpustakaan libCtersebut belum siap. Biasanya masalah hilang ketika proyek dikompilasi ulang. Tetapi fakta bahwa ini terjadi sama sekali menunjukkan masalah serius dengan QMake. Dan masalah ini tidak dapat diselesaikan dengan menggunakan sesuatu sepertilibA.depends = libB... Mungkin (dan, mungkin, memang demikian), saya melakukan sesuatu yang salah, tetapi baik saya maupun kolega saya tidak berhasil mengatasi masalah tersebut. Satu-satunya cara untuk menyelesaikan masalah dengan urutan build library adalah dengan menggunakan kustomisasi CONFIG += ordered, tetapi karena itu, dengan menghilangkan build paralel, performa akan sangat menderita.



QBS dan CMake



▍Mengapa QBS kalah dari CMake?



Pesan tentang berakhirnya dukungan untuk QBS (Qt Build System, Qt build system) sangat mengejutkan saya. Saya bahkan merupakan salah satu pemrakarsa upaya untuk mengubah ini. QBS menggunakan sintaks bagus yang akrab bagi siapa saja yang pernah menulis kode QML. Saya tidak dapat mengatakan hal yang sama tentang CMake, tetapi setelah saya bekerja dengan sistem pembangunan proyek ini selama beberapa bulan, saya dapat dengan yakin menyatakan bahwa beralih dari QBS adalah keputusan yang tepat, dan bahwa saya akan terus menggunakan CMake ...



CMake, meskipun memiliki beberapa kekurangan sintaksis, bekerja dengan andal. Dan masalah QBS lebih bersifat politis daripada teknis.



Ini adalah salah satu faktor utama yang memaksa programmer yang tidak senang dengan ukuran Qt (baik dari segi jumlah baris kode dan ukuran library) untuk mencari alternatif. Selain itu, banyak orang sangat tidak menyukai MOC. Ini adalah kompilator meta-objek yang mengubah kode C ++ yang ditulis menggunakan Qt menjadi C ++ biasa. Berkat kompilator ini, Anda dapat, misalnya, menggunakan konstruksi yang nyaman, seperti yang memungkinkan Anda bekerja dengan sinyal.



▍ Alternatif untuk QBS



Selain QBS, kami juga memiliki sistem pembangunan proyek seperti build2, CMake, Meson, SCons. Mereka, di luar ekosistem Qt, digunakan di banyak proyek.



▍ Dukungan QBS yang buruk di IDE



Sejauh yang saya tahu, satu-satunya IDE yang mendukung QBS adalah QtCreator.



▍ Persatuan brilian vcpkg dan CMake



Ingat bagaimana saya membenci masalah dengan dependensi eksternal di atas? Jadi, tidak mengherankan betapa banyak emosi positif yang disebabkan oleh pengelola paket vcpkg. Satu perintah sudah cukup untuk menginstal ketergantungan! Saya pikir vcpkg dapat berguna untuk programmer C ++.



Sintaks CMake yang tampaknya tidak menarik



Jika Anda menilai CMake dari sepuluh tautan teratas yang ditemukan oleh Google, tampaknya sistem ini menggunakan sintaks yang sangat tidak menarik. Tetapi masalahnya di sini adalah bahwa Google adalah yang pertama menampilkan item CMake lama dari Stack Overflow, tertanggal 2008. Tautan ke dokumentasi lama untuk versi CMake 2.8 juga ditemukan. Sintaks yang digunakan saat bekerja dengan CMake bisa sangat bagus. Faktanya adalah bahwa menggunakan CMake terutama melibatkan penggunaan konstruksi yang ditunjukkan di bawah ini (ini adalah versi singkat dari file CMakeList.txt dari proyek 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 mempercepat CMake



Peran CMake hanya menghasilkan instruksi untuk sistem pembangunan proyek yang dipilih pengembang. Ini bisa menjadi nilai tambah yang besar saat bekerja dengan orang-orang yang menggunakan Visual Studio daripada Qt Creator. Saat menggunakan CMake, Anda dapat (dan harus) memilih Ninja sebagai sistem build default Anda. Mengompilasi proyek menggunakan bundel CMake + Ninja sangat bagus. Keduanya dapat ditemukan di kotak alat Pemeliharaan Qt. Antara lain, alat ini dapat menangani perubahan dengan sangat cepat dalam pendekatan pengembangan berulang. Faktanya, semuanya bekerja sangat cepat sehingga ketika menggunakan Godot dengan SCons, saya sangat ingin menggunakan CMake di sini juga.



Vcpkg memungkinkan CMake bersinar



Mengelola ketergantungan dalam proyek C ++ bukanlah tugas yang mudah. Untuk mengatasinya, banyak proyek bahkan menempatkan DLL yang diperlukan di repositori Git mereka. Dan ini buruk, karena ini tidak perlu meningkatkan ukuran repositori (kami tidak menyentuh Git LFS di sini). Satu-satunya kekurangan vcpkg adalah bahwa manajer paket ini hanya mendukung satu versi global dari sebuah paket (yaitu, Anda harus menginstal sendiri versi vcpkg yang berbeda, tetapi ini sedikit hack, dan ini jarang diperlukan). Benar, dalam rencana pengembangan proyek, Anda dapat melihat bahwa itu berjalan ke arah yang benar.



Perintah berikut digunakan untuk menginstal paket:



vcpkg install crashpad


Ketika bekerja pada ScreenPlay, kita hanya menciptakan install_dependencies_windows.bat dan install_dependencies_linux_mac.sh script untuk mengkloning repositori vcpkg, membangun dan menginstal semua dependensi kami. Saat bekerja dengan Qt Creator, Anda perlu menulis ke CMAKE_TOOLCHAIN_FILEjalur relatif ke vcpkg. Selain itu, vcpkg perlu diberi tahu OS apa dan arsitektur apa yang kita gunakan.



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


Apakah Anda perlu memasang pustaka lain? Untuk melakukan ini, cukup gunakan perintah formulir vcpkg install myLibToInstall.



Hasil



Pendekatan menggunakan yang terbaru dan terpopuler memiliki kelebihan. Tapi apa yang harus dilakukan, misalnya, ketika membangun sistem dengan potensi besar seperti QBS tiba-tiba tersesat? Pada akhirnya, pengembang sendiri yang memutuskan apa yang akan digunakan dalam proyeknya. Itulah mengapa saya memutuskan untuk mentransfer proyek saya ke CMake. Dan, harus saya katakan, itu keputusan yang tepat. Hari ini, di tahun 2020, CMake terlihat cukup bagus.



Apakah Anda menggunakan CMake dan vcpkg?










All Articles