Search code examples
qtcmakevcpkg

Qt platform DLL qwindows.dll not copied to platform directory on build in Visual Studio with CMake and vcpkg


I have distilled this very simple CMake project that uses vcpkg and builds a dead simple Qt gui application just showing a main window. I can get it to build successfully in Visual Studio 2022 but I cannot get it to run seamlessly. The problem arises because the Qt platform DLL isn't copied to the output location with the other DLL dependencies in the post build step.

The qwindows.dll (or qwindowsd.dll) file is meant to be copied to the output location with the executable and other DLLs but in a platforms\ subdirectory. This does not happen during a build, but if I create the directory and copy it manually then the application works.

To me this is something that should work seamlessly as part of the build process so I'm curious to know if I'm doing something wrong or I've set something up incorrectly.

Now I know that the simplest hacky solution would be to manually put a CMake post build step to copy the appropriate DLL from the vcpkg_installed directory to the output directory. But this seems like a hack as the system should handle this already otherwise many other people would be having this issue as well.

So the questions I'm asking:

  • Am I missing something trivial here in the configuration?
  • Am I not understanding something with how CMake + Qt work?
  • Is this combination of CMake, vcpkg, and Qt a supported configuration that is expected to work?

The CMakeLists.txt is (and mostly taken from Qt's own example):

cmake_minimum_required(VERSION 3.22 FATAL_ERROR)

project(QtTest LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_standard_project_setup()

add_executable(QtGuiTest
    Source/Main.cpp
    Source/MainWindow.cpp
    Source/MainWindow.hpp
)

target_link_libraries(QtGuiTest PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets)
set_target_properties(QtGuiTest PROPERTIES WIN32_EXECUTABLE ON MACOSX_BUNDLE ON)

The CMakePresets.json is:

{
    "version": 3,
    "cmakeMinimumRequired": {
        "major": 3,
        "minor": 22,
        "patch": 0
    },
    "configurePresets": [
        {
            "name": "default",
            "displayName": "Default",
            "generator": "Visual Studio 17 2022",
            "architecture": "x64",
            "toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake"
        }
    ]
}

The vcpkg.json is:

{
    "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
    "name": "qtguitest",
    "version": "0.1",
    "dependencies": [
        "qtbase"
    ]
}

Then I execute CMake to build out of the source tree with the default preset.


The code for the application is literally this:

// MainWindow.hpp
#pragma once
#include <QtGui>

class MainWindow : public QWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWindow* parent = nullptr);
};

// MainWindow.cpp
#include "MainWindow.hpp"

MainWindow::MainWindow(QWindow* parent)
    : QWindow(parent)
{}

// Main.cpp
#include <QApplication>
#include "MainWindow.hpp"

int main(int argc, char* argv[])
{
    QApplication q_application{argc, argv};
    MainWindow main_window;
    main_window.show();
    return q_application.exec();
}

For reference I'm using:

  • The latest Visual Studio 2022 Community Edition (as of 1/10/2022)
  • CMake 3.22 installed (though vcpkg downloads 3.24 and uses that)
  • vcpkg (as of 1/10/2022)
  • Qt 6.3.2 is being installed

Solution

  • Thanks to help from the other answers here I was able to figure this snippet out to add to the CMake configuration I had above.

    add_custom_command(TARGET QtGuiTest POST_BUILD 
        COMMAND Qt6::windeployqt
        ARGS $<TARGET_FILE:QtGuiTest>
    )
    

    Which ends up calling the windeployqt application in the simplest manner in a post-build step.