Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-109444

Qt's CMake deployment API Error: Extra libraries copied

    XMLWordPrintable

Details

    • Bug
    • Resolution: Fixed
    • P2: Important
    • 6.5.4, 6.6.1, 6.7.0 FF
    • 6.3, 6.4.0, 6.4.1, 6.5
    • Build System: CMake
    • None
    • Windows 11
    • Windows
    • 266c2d23a (dev), 854ee1c03 (dev), a2098df70 (6.6), d0513abe1 (6.6), 87ad91cd7 (6.5), 8f62d5e72 (6.5)

    Description

      Good afternoon.
      I'm using the new Qt API for CMake to deploy a QtQuick/Qml based application.
      I tested this behavior on Windows 11 Pro on different versions of the Qt library (branches 6.3 / 6.4 / dev).
      I am creating a new Qt Quick Application in Qt Creator. In the CMakeLists.txt file, I add calls for deployment. Here are the files that make up the project.

      CMakeLists.txt:

      cmake_minimum_required(VERSION 3.16)
      
      project(QmlAppDeployTest VERSION 0.1 LANGUAGES CXX)
      
      set(CMAKE_AUTOMOC ON)
      set(CMAKE_CXX_STANDARD_REQUIRED ON)
      
      set(CMAKE_BUILD_TYPE Release)
      
      find_package(Qt6 6.2 COMPONENTS Core Qml Quick REQUIRED)
      qt_standard_project_setup()
      
      qt_add_executable(QmlAppDeployTest
          main.cpp
      )
      
      qt_add_qml_module(QmlAppDeployTest
          URI QmlAppDeployTest
          VERSION 1.0
          QML_FILES main.qml
      )
      
      set_target_properties(QmlAppDeployTest PROPERTIES
          MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
          MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
          MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
          MACOSX_BUNDLE TRUE
          WIN32_EXECUTABLE TRUE
      )
      
      target_link_libraries(QmlAppDeployTest
          PRIVATE Qt6::Qml Qt6::Quick)
      
      install(TARGETS QmlAppDeployTest
          BUNDLE DESTINATION .
          RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
      )
      
      qt_generate_deploy_qml_app_script(
          TARGET QmlAppDeployTest
          FILENAME_VARIABLE deploy_script
      )
      install(SCRIPT ${deploy_script})
      

      main.cpp:

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      
      int main(int argc, char *argv[])
      {
          QGuiApplication app(argc, argv);
      
          QQmlApplicationEngine engine;
          const QUrl url(u"qrc:/QmlAppDeployTest/main.qml"_qs);
          QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                           &app, [url](QObject *obj, const QUrl &objUrl) {
              if (!obj && url == objUrl)
                  QCoreApplication::exit(-1);
          }, Qt::QueuedConnection);
          engine.load(url);
      
          return app.exec();
      }
      

      main.qml:

      import QtQuick
      import QtQuick.Controls
      
      Window {
          id: window
          width: 640
          height: 480
          visible: true
          title: qsTr("Hello World")
      
          Column {
              anchors.centerIn: parent
              width: window.width / 3
              height: window.height / 3
              Button {
                  text: "Request"
                  width: 150
                  height: 30
              }
          }
      }
      

      Next, I configure, build, and install with the following commands:

      "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" amd64
      
      cmake -G "Visual Studio 16 2019" -A x64 -D CMAKE_PREFIX_PATH="c:/Qt6.4.0/6.4.0/msvc2019_64" ../QmlAppDeployTest
      
      cmake --build . --config Release
      
      cmake --install . --config Release --prefix c:/qml_app_deploy_test
      

      Next, I explore the c:/qml_app_deploy_test directory and see which libraries have been copied there.

      First, let's look at the c:/qml_app_deploy_test/bin directory
      Here is a list list of his files:

      d3dcompiler_47.dll
      opengl32sw.dll
      QmlAppDeployTest.exe
      qt.conf
      Qt6Core.dll
      Qt6Gui.dll
      Qt6Network.dll
      Qt6OpenGL.dll
      Qt6Qml.dll
      Qt6QmlModels.dll
      Qt6QmlModelsd.dll
      Qt6QmlWorkerScript.dll
      Qt6QmlWorkerScriptd.dll
      Qt6Quick.dll
      Qt6QuickControls2.dll
      Qt6QuickControls2d.dll
      Qt6QuickControls2Impl.dll
      Qt6QuickControls2Impld.dll
      Qt6QuickLayouts.dll
      Qt6QuickLayoutsd.dll
      Qt6QuickShapes.dll
      Qt6QuickShapesd.dll
      Qt6QuickTemplates2.dll
      Qt6QuickTemplates2d.dll
      Qt6Svg.dll
      vc_redist.x64.exe
      

      We can see that in addition to release versions, debug versions have also been copied for some libraries.

      We also examine the contents of the c:/qml_app_deploy_test/qml/QtQml directory:

      Models/modelsplugin.dll
      Models/modelsplugind.dll
      Models/qmldir
      WorkerScript/workerscriptplugin.dll
      WorkerScript/workerscriptplugind.dll
      WorkerScript/qmldir
      qmldir
      qmlplugin.dll
      qmlplugind.dll
      

      Not only release versions are also copied here, but also debug versions.
      The same situation is also observed in other subdirectories, for example in c:/qml_app_deploy_test/qml/QtQuick.

       I found the cause of this problem. She is here:
      C:/Qt6.4.0/6.4.0/msvc2019_64/lib/cmake/Qt6Qml/Qt6QmlDeploySupport.cmake.
      I also provide links to this code in the Qt repositories:

      https://code.qt.io/cgit/qt/qtdeclarative.git/tree/src/qml/Qt6QmlDeploySupport.cmake#n185

      https://github.com/qt/qtdeclarative/blob/dev/src/qml/Qt6QmlDeploySupport.cmake#L185

       Here is the code (this is a fragment of the _qt_internal_deploy_qml_imports_for_target definition function):

      list(FILTER files INCLUDE REGEX "^(.*/)?(lib)?${entry_PLUGIN}.*\\.(so|dylib|dll)(\\.[0-9]+)*$") 

      This uses a regular expression to search for library files that match the plugin name.
      This uses a regular expression to search for library files that match the plugin name. Let's take a look at this snippet:

      ${entry_PLUGIN}.*\\.
      

      If the plugin name is qtquick2plugin, then this fragment will match the lines:

      qtquick2plugin.
      qtquick2plugind.
      

      What is happening. This code finds the library files for each passed plugin, both release and debug versions. And as a result, when installing the project (cmake --install ...), all these found files will be copied. And as a result of this copying of debug versions of plugins, their debug dependency libraries will also be copied to the c:/qml_app_deploy_test/bin directory.

      I experimented and changed the C:/Qt6.4.0/6.4.0/msvc2019_64/lib/cmake/Qt6Qml/Qt6QmlDeploySupport.cmake file in the installed Qt library so that the specified line was:

      list(FILTER files INCLUDE REGEX "^(.*/)?(lib)?${entry_PLUGIN}\\.(so|dylib|dll)(\\.[0-9]+)*$")
      

      And after that, I called the installation of the project again (after deleting the directory from the previous installation):

      cmake --install . --config Release --prefix c:/qml_app_deploy_test
      

      and now ONLY release version libraries have been copied.

      With this, my application starts correctly.
      Perhaps you could use this fix. But maybe I don't know about some cases when it won't work.

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              jbornema Joerg Bornemann
              rumgot rumgot
              Votes:
              2 Vote for this issue
              Watchers:
              9 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: