2

Every time a new Qt project is built for first time in Visual Studio, even with the VS Tools installed, I have to copy some Qt-related binary files (Qt5Core.dll, platform files...). Otherwise, when running from Visual Studio, Qt5Core.dll (or debug one) are correctly found but not the platform DLL:

enter image description here

Obviously, it would also fail when running done from outside the IDE, for example, during unit testing on automated builds.

Qt's has a tool to do so, called windeployqt, which basically looks for dependencies (Qt) and copy them. For example:

c:\Qt\Qt5.12.1\bin\windeployqt c:\projects\qt-project\Release --release

will analyze executables in c:\projects\qt-project\Release and copy required DLLs, plugins, translations and other related binaries to such location.

I'm interested in how to integrate windeployqt into the build workflow of Visual Studio so this process is automatic (even when checked out in different computers).

cbuchart
  • 10,847
  • 9
  • 53
  • 93

2 Answers2

4

You can obviously create a batch file and execute it, but take in mind that you have to do it after compiling the project, since the tool will look at the executable files. Also, you'll have to deal with build paths and Qt installation dir location, in order to make it portable across systems.

(See at the end of this answer for an update on this)

A more convenient way to do it is to configure windeployqt as a post-build event in your project (Project properties > Build Events > Post-Build Event). I'm documenting this here since I couldn't find any explicit reference and it took me a while to figure it out.

To deal with portability:

  • $(QTDIR): this variable expands to the installation path of current Qt version (I'm assuming it is a Qt project, of course, and that Qt VS Tools are installed). Use it to locate windeployqt (under $(QTDIR)\bin\).

  • $(OutDir): expands to the build directory of the executable. As usual, quote it to deal with paths with spaces. The issue here is that $(OutDir) usually ends with a back-slash (\), so when "$(OutDir)" is expanded it will create a escaped character \" that will wrongly interpreted. In order to fix it you can trim the leading slash: "$(OutDir.TrimEnd('\'))" (credits).

  • $(Configuration): expands to the name of current configuration (usually Debug or Release, read below for other configuration names). Now, windeployqt is case sensitive regarding the --debug or --release parameters, and configuration name is Title cased. To lower-case it: --$(Configuration.toLower()) (credits). This step is just for having a common command, and can be skipped by putting the --debug or --release flag manually.

With this, the complete post-build command is as follows:

"$(QTDIR)\bin\windeployqt.exe" "$(OutDir.TrimEnd('\'))" --$(Configuration.toLower())

This command can be applied uniformly across all platforms and configurations of the projects.

Now, if you have other configurations than Release and Debug you can either:

  • Modify the command by adding --debug or --release accordingly, or

  • Create a custom property page for "debug-based configurations" and "release-based configurations" and set a variable (such as BaseConfiguration) to Debug or Release, then use this new variable in the command instead.

Update

Since a few versions ago of the Qt VS Tools (not sure which, but at least 2.7.1), the deployment tool can be added to the build chain directly from the project's properties sheet:

enter image description here

cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • 1
    When using "Run Deployment Tool = Yes" in Qt Project Settings, how to set ```--qmldir``` option for executing windeployqt? Because of that I got so many ```module "QtQuick.blahblah" is not installed``` warnings in my app running. – WOOSEOK CHOI Oct 25 '22 at 08:36
1

You don't have to copy those dll's if you only want to run and/or debug your application from Visual Studio, you can add the dependencies path(s) to the debugger environment in Visual Studio.

You can do that in Visual Studio like this:

  • right click on the vcxproj file in the Solution Explorer
  • from that context menu click on Properties
  • in the dialog that opened navigate to Debugging (in the left panel)
  • in the right panel look for Environment and in there you can use something like this:

    PATH=$(QTDIR)\bin;$(PATH)

Note: when you edit back that you can see some encoding for the ';' that is not a problem, you only need to be careful when you edit that so that you don't miss a ';' between any 2 paths.

If the project depends on more libraries you can add more environment paths in there and don't forget to edit that for all the build options (Release/Debug/x64/x86/etc) and you can define your own variables with the base path for each external library.

Now back to Qt, that QTDIR variable is defined in the .user file, for all build configurations you'll have something like:

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <QTDIR>C:\Qt\5.12.1\msvc2017_64</QTDIR>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
    <LocalDebuggerEnvironment>PATH=$(QTDIR)\bin%3b$(PATH)</LocalDebuggerEnvironment>
  </PropertyGroup>

A problem that i had with that was that the QTDIR was swapped with the LocalDebuggerEnvironment (i meant that LocalDebuggerEnvironment is defined first) and obviously that doesn't work, so if it's the case, just manually swap those 2 defines with your favorite text (or xml) editor, so that QTDIR is defined before.

So i suggest this method instead of using windeploy as part of a custom build step, use windeploy for your script that generates (or prepare the files for) the installer.

Zlatomir
  • 6,964
  • 3
  • 26
  • 32
  • Thanks! I'll a look at this, but the main problem I've had when running from VS are platform DLLs and plugins, not correctly found by VS. Also, some automated tests are run from outside VS during automated compilations. I think I was not cleared enough about this in the question. – cbuchart Feb 20 '19 at 14:53
  • Using this VS will find the dlls. As for the automated tests are those used by all developers on all development computers? If no, than maybe those automated tests can grad the exe from the build path and then use windeploy (or other script that brings the dependencies), i whoudn't want windeploy to copy those dependencies every time you build (not to mention that windeploy only works for Qt and doesn't copy any other dependencies) – Zlatomir Feb 20 '19 at 14:57
  • Yes, tests are always passed on every full compilation (can be skipped but not done usually). Regarding other dependencies, they are solved using other tools, the issue with windeployqt is that it requires the executable, so it must be run _after_ building, not before (as other ones that just analyse the project). Regarding the copied files, not a huge problem (yet) since added time is almost neglective, but agree it is a thing to take into account. – cbuchart Feb 20 '19 at 15:04
  • Also, we don't commit .user files since they depend on each user configuration, some way to apply this changes on checkout (may be it is for a different question)? – cbuchart Feb 20 '19 at 15:05
  • 1
    Yes, .user file won't be on version control (since every member can have dependencies at other paths). But, still having the dependencies copied after every build is overkill. Maybe a run once (python) script will be better, if you don't like the default way and you need to run as stand-alone (for tests) – Zlatomir Feb 20 '19 at 15:11
  • BTW, I've just tested the .user suggestion, and it still doesn't find the platform plugins. (It was already finding correctly the main Qt DLLs before the change). – cbuchart Feb 20 '19 at 15:11
  • By default it does. Qt has api for that plugins, are you playing with that? – Zlatomir Feb 20 '19 at 15:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/188761/discussion-between-cbuchart-and-zlatomir). – cbuchart Feb 20 '19 at 15:19