Qt发布,无法找到qwindows.dll
2014-06-13 14:36
375 查看
I’ve written about deploying a simple Qt app, but what about deploying a more complex, “real” Qt app. This means copying all the needed files: besides the
main executable file there usually are some shared libraries, e.g. DLLs, and some other files like configuration or certificate files. In this blog post I’ll concentrate on getting the binary executable files setup correct; of course there can be other important
files, like the
First there’s the option of static linking i.e. one build that packs all of Qt’s DLLs and your code together in a single .exe file. This hugely simplifies
deployment, but it’s a time consuming process that can be tricky; of course if you distribute large quantities of your software, static linking is definitely something you should try.
But if you’re not yet targeting a couple of millions of PCs (or a similar number
)
then you’re building your Qt app the normal, dynamic way. And that app structure in Qt depends heavily on shared or dynamically loaded libraries; on your deployment PC the Qt installer sets these up for you, but on other PCs you need to do it yourself. You
can either use an installer, for example Qt has a good one, or copy the files
manually.
A good idea here is to find a way to install your Qt app on a vanilla computer with minimal intrusion, because maybe you don’t have administrative or physical access to it, instead perhaps relying on a network share or FTP. For Windows this means no
writing to the registry (once the app is installed, it can use the registry for preferences or similar stuff, but this is about the install process) or create files in “system” locations like C:\Windows etc. For Linux and Macs, it means no fiddling with .conf
files in /etc and no file copying to /usr/lib or similar places.
First step anyway is to build your app in release mode and collect all the needed files together. If you’ve read myearlier
post about distributing a bare-bones Qt app, the files and directory structures used in that post are a good start. Also while it is possible to compile and build a Windows Qt app on Mac, here I’m assuming you’re using a Windows PC for Windows deployment,
a Mac for Mac deployment and a Linux installation for Linux stuff. (Re. Linux: I’m only using/testing Ubuntu and Debian, and on these the Qt installation files are the same, but other distros may differ here.)
The DLL (or .so and .dylib) files that a Qt app needs for successful launch can be divided into 3 flavors:
For
Windows, say a Qt widgets app, they are at least
For Linux, they’re
on the Mac they’re
A “real” Qt app most likely requires some more.
Note: for a typical Qt development installation, the library files/DLLs can be found in two different places, one is in your compiler directory, for example …\mingw48_32\bin, and the other
is a subdirectory of QtCreator. Don’t use the files from the latter place, those DLLs in QtCreator’s subdirectories are for QtCtreator’s own use, it’s a Qt app (of course!). In some cases, like in Linux, the DLLs are identical to the ones in the compiler directory;
in other cases, like for a MinGW-flavored installation of Qt on Windows, they are not (QtCreator is built using Visual Studio and those .dlls do not work for a Qt app built with MinGW!). Instead, always use the library files in your compiler’s …\bin
directory.
A Qt app, like other apps, relies on the OS to load those library files, which means that they must be placed where the OS can find them. On Windows, this means either next to the .exe file in the same directory
or in a directory specified in the search path, for example C:\Windows\System32. On a PC with Qt installed, the DLLs are located by adding the directory to the search path, either by QtCreator when you run your app from it, or by manually invoking
Qt’s compiler’s bin directory.
When copying the DLLs to another PC without Qt installed, usually you don’t want to mess with the search path on other computers, instead placing the DLLs together with the .exe file is probably the best solution.
On Linux, placing the .so files next to the .elf file in the same directory does not cause them to be found/loaded automatically like in Windows; you can add directories to the search paths or ld.so’s .conf
files, but a less intrusive way is using the rpath setting in the .elf file, and that’s what Qt
does. On your development PC with Qt installed, when building your app, QtCreator sets the
to the lib subdirectory inside Qt’s installation directory (where the .so files for Qt are located).
This is quite handy when you want to launch your app from Nautilus or Terminal (don’t need any .bat files like in Windows!) but when you later deploy your app to another Linux computer without Qt installed, then that
is guaranteed to be wrong
and needs to be fixed.
Note: you can get lucky, for example on Ubuntu, there usually is a Qt installed in /usr/lib/i686-linux-gnu or /usr/lib/x86_64-linux-gnu, so your app might run anyway (ld.so, the dynamic linker/loader, gets those paths from the .conf files in /etc/ld.so.conf.d).
But beware of the versioning problem, the Qt supplied by Ubuntu might be too old for your app to launch ok.
For how to fix that
previous post about deploying a bare bones app for Linux.
On Macs also there’s no default loading of .dylibs when they’re placed together with the .elf file. Apple in Leopard (10.5) introduced a rpath
setting similar to the one in Linux. One minor problem is that there’s no
available for OSX to set the rpath; i.e. it can only be set at link time from QtCreator. And another complication is that the library files are (mostly) placed separately, each in their own directory structure.
All this means, while it’s no problem launching your Qt app from Finder or from Terminal on your dev. Mac with Qt installed, you’re up the creek without a paddle when deploying your Qt app to another Mac with no Qt on it. Since the
not be changed easily, you’ll have to run Apple’s
.dylib and framework of Qt it depends on. And for every Qt .dylib/framework that has a dependency on another .dylib/framework, e.g. QtGui.framework depends on QtCore.framework, those needs a whacking with install_name_tool as well.
Thankfully, someone with a brain has written a utility for this called macdeployqt. You run it on your development Mac, I’ve written about in my
previous post.
Some MSVC redist installs on a typical Windows PC
While all 3 platforms depends on these kinds of .DLLs, on Linux and Macs it’s presumed that those files (like libstdc++.so.6 or libstdc++.6.dylib) are present and recent enough to work, but on Windows, mostly
because of the variety of compilers, this needs to be addressed when deploying to another PC. The easiest is to copy them together with the Qt specific DLLs, and in my
previous post I show you how.
However, for the Microsoft compiler DLLs, they recommend not just simple copying them (although that works just fine). Instead you should copy and install a vcredist package (can be found in the Qt’s vcredist
subdirectory), thereby installing the MSVC dlls not together with your app, but somewhere within the bowels of C:\Windows.
The reason for this extra step is to give Microsoft an opportunity to update those .dlls if needed, in case they find a bug or security problem in them. This is in theory a good idea, but for me, it also has
during the years meant a couple of early Monday morning calls from customers complaining about my broken app. And discovering that the reason was Microsoft updating their dlls. To be fair, this was not the Visual C++ dlls, two that I can remember were: ATL
security update and an ADO update.
Welcome
to an interesting nook and cranny of Qt deployment, the DLLs that Qt loads by itself! The DLLs mentioned above, they are all standard DLLs loaded by the OS which means you have to know how Windows, Mac and Linux loads library files. But also
if a file is missing, you will get an error, a message box or some other diagnostic message, like “This application has failed to start because Qt5Core.dll was not found.” then you have something to google on.
Qt plugins on the other hand are more sinister in this regard, for many of them when they are missing/not found in the expected place, your Qt app will fail silently
No
error message or diagnostic output, just an app that doesn’t start or exhibits reduced functionality. For example, a Qt Quick app that cannot find the needed QML/QtQuick plugins will instead display an empty white window. Also when trying to find the DLLs
your app depends on, when running a tool like Dependency Walker or
Linux, the Qt plugin DLLs will not show upbecause these tools only display the normal DLLs requested/imported by the app, and not the plugin DLLs that Qt only knows about. To see them, you need to first launch your app (so that they are loaded into
memory) and then use a tool like ListDLLs for Windows or the
built-in
Another gotcha re. these plugin DLLs: even though you are super sure you’ve placed them in the correct place, you can still be greeted with “… could not find or load the Qt platform plugin…”
This can happen because a DLL that these guys depend is missing. Since Qt is the loader (and not the OS) you won’t get the usual diagnostic “not found” message. Running Dependency Walker or ldd for Linux on the DLL in question, can be helpful for
debugging these kind of errors.
For example, the Visual Studio-flavored non-OpenGL platform plugin
and in Linux
the X server stuff. Also an additional gotcha: for non-OpenGL MSVC-flavored deployments, that
with the
it’s the OS that loads other files it depends on, like
So how does Qt load these plugins, what are the rules? At start, Qt makes a list of directories where it hopes to find the plugin DLLs. For such a plugin directory to be valid, it has to contain some subdirectories with predetermined names like:
These subdirectories are where Qt expects to find the plugins DLLs. It does so by enumerating all files in the subdirectory, looking for matching plugin
keys. When you install Qt, it creates such a plugin directory directly below the compiler, for example
The most important plugin type is the
plugins and are needed by all Qt apps (even a minuscule Qt app like the bare bones one in my previous post), and the default one is qwindows.dll (libqxcb.so for Linux or libqcocoa.dylib for the Mac). This is Qt’s QPA (Quarter Pounder Advanced™ just
kidding, it stands for Qt Platform Abstraction layer), it’s responsible
for many OS-specific things, for example translating calls like
calls.
I mentioned Qt doesn’t care about the plugin filenames, only about the subdirectory names, let me give you an example:
The filenames for plugins are immaterial
If I rename qwindows.dll to grapefruit.jpg, Qt will still happily load it as a DLL. Contrast that with for example when Windows wants to load
it can be in any directory along the PATH or next to the .exe file for the app, Windows doesn’t really care, as long as the filename is correct. Qt instead fubars if the subdirectory
be found.
Thankfully, for these platform plugins, Qt do display an error message in case they cannot be found. In Windows Qt displays a message box, for Macs and Linux these errors usually can be seen when you launch
your app from Terminal. (True also for the normal DLLs.) So if Qt’s plugins are not deployed correctly, that error message is a good diagnostic, my previous
post shows these errors in more glorious detail.
Let’s look at how Qt’s list of plugin directories are determined at app start, and how you can use these rules for successful app deployment.
Remember that this list specifies the main plugin directory (which is
DLLs themselves, are stored in the subdirectories below it.
Actually there are 5 (!) different choices for establishing the plugin directory:
Hexediting Qt’s plugin path
This is the big wheel approach to plugin lookup, favored by Qt’s installer. When you install Qt on your development PC, the installer patches Qt5Core.dll with the path you specified for your convenience. This means whenever you start Qt apps on your development
machine, the plugins will always be located fine and dandy. (From the point of view of deployment to another PC, this instead could be considered a disservice. Nevermind.)
To see the current path setting (note: for Windows you might need to download Sysinternal’s
strings utility):
Then if you’re into hex editing yourself, you can apply a new setting for deployment:
Changing to a path more suitable for deployment
You can change to another absolute path, but a relative path works too, it means Qt will use the directory where the .exe file is and append the plugin path to it.
For example, assume you’ve placed your Qt app in the directory
if you’ve hex edited
the directory
When I tested on Windows with a relative path I had to prefix it with C: which obviously doesn’t work on Linux and Macs. So while this is a viable method for plugin deployment, I suggest you leave this option
to the big wheels
Note: remember if you’re running your app in Debug mode then the settings in
apply,not
Setting the environment variable
Using an environment variable might be an easier option than hex editing Qt5Core.dll, and the effect will be the same, for example:
will perform the same feat as above, Qt will look for
Of course you can also set an absolute path this way. And if you want a bonanza of plugins directories, you can append additional paths separated with ; (or : in Linux and Macs).
Adding the plugin path in main()
You can also specify a plugin path in your code, but since Qt loads the plugins when QApplication is constructed, your window of opportunity is to do it before QApplication’s constructor is called.
The call above is a 3rd alternative for telling Qt to look for
the same example as above).
Creating a
This is a popular method of setting up a path to the plugins, used for example by the QtCreator app and the macdeployqt
utility on Macs. Create a text file, like this:
If such a file exists in the same directory as the app’s .exe file, Qt will read it and add the
to its list of plugin directories. The example above accomplishes the same thing as in the previous examples, it causes Qt look for
One caveat here if you’re on Windows: backslashes in the
you should use Linux-style forward slashes.
How does this work? Well, when your app starts, Qt as a freebie adds the directory where your app’s .exe file is located to its list of plugin directories.
Note that this is not the same as the examples above, in those we instructed Qt to look for plugins in
this default setting tells Qt to look for plugins in
or an equivalent
So if we take the example above again; you’ve deployed your app to the directory
This means that Qt automatically will look for
For example, if you look at my previous post you’ll see that for deployment of that bare bones app,
I always go for this option, i.e. placing the
Q: “Then why does Qt Creator go through the trouble of creating a
for itself, when it suffices just to copy the plugin subdirectories into the app’s directory?”
One reason could be to reduce litter in the app’s main directory, if we look at Qt Creator’s
it has the line
sense to stash away all those subdirectories in a separate
Another reason for creating a qt.conf file:
Mac there’s an app bundle standard that plugins should reside in their own directory called
Remarks: if you use a
a spelling error in it, that can cause plugin loading to fail. Also the last two methods (the most popular ones) are currently slightly more brittle due to an obscure
bug, for example if you call QStyleFactory::keys() before QApplication a(argc, argv) in your main.cpp, this preempts the path to the .exe file and a path in
be setup as eligible plugin directories.
Finally, if you’re still running into plugin loading problems, you can turn on a trace of the plugin loading process, by setting the environment variable
a nonzero value, like this:
(for Linux and Macs instead use
window. For Linux and Macs you’ll see lines something like “QFactoryLoader::QFactoryLoader() checking….” displayed in Terminal, but in Windows Qt routes the output to the OutputDebugString() API, so nothing will be displayed in the CMD window. The output can
be seen using Visual Studio or Qt Creator, which isn’t very helpful if you’re experiencing the plugin problems on a non-development PC. An alternative is to download a utility: DbgView
from Sysinternals and open it before you launch your app you’ll be fine.
hardwired in Qt’s plugin loader? I lied, you can actually change
is different from the previous 5 choices, since they are for specifying the
while this setting is for changing only the
useful? Really don’t know, but I’m guessing for debugging/testing. Also note that this option is not available for Qt Console apps, only Quick- and Widgets-flavored ones.
Say you want to change to instead use the subdirectory
set/export an environment variable:
or give a command line argument when launching your app:
Note that if this is a relative path (like in my example) then it’s relative to the app’s .exe file, so for a more convoluted case, if you’re using a
that overrides the default plugins directory
then if
you would instead have to type:
in your Qt folder: QtCreator. Besides creating the version specific (like
are, Qt’s installer also creates the
find a Qt Creator.app (which is a directory, you open it with a rightclick and Show Package Contents in Finder).
QtCreator is packaged ready to deploy, i.e. you can copy it (the directory or in the Mac case, the app) to another computer and it will start just fine. (For
Windows, you might need to install the vcredist_msvc2010 runtime located in the QtCreator’s lib subdirectory.) If you copy it to a PC without a Qt installation, it might not compile and build apps, but it would still function well as a text/code editor
So let’s look on how it solves its deployment, first the normal DLLs:
In Windows, all the needed DLLs are placed together with
which is installed using the vcredist package I mentioned earlier).
In Linux, the .so files are in a neighboring subdirectory:
the .elf file has a custom
In Macs, all the .dylib and framework files QtCreator needs are included in the app bundle (if you do
in the MacOS folder, you’ll see for example
the same) as when you run the utility
Then the plugin DLLs, how are they located? Well, if we start by looking at
a
Linux and Mac it’s more or less the same setting).
Obviously there’s no “/work/build” directory, so clearly the option of using
specifying the plugin directory is unused by QtCreator.
(BTW, this is one of the reasons why this Qt5Core.dll is not replaceable with the Qt5Core.dll in the compiler directory, because the
that one is used and expected to be valid.)
So, QtCreator does not set any environment variables and does not call
main.cpp, nor is the default directory option used. Instead (as I’ve already mentioned above) QtCreator has a
its plugin directory, using the relative path
If you want to experiment, momentarily rename or move away the qt.conf file, and then try to start QtCreator. You’ll see that infamous message “… could not
find or load the Qt plugin …. “, same for any other Qt app
Don’t
forget to restore the qt.conf file!
main executable file there usually are some shared libraries, e.g. DLLs, and some other files like configuration or certificate files. In this blog post I’ll concentrate on getting the binary executable files setup correct; of course there can be other important
files, like the
qmldirdeclaration file in the QtQuick.2 subdirectory etc. but that’s a topic for another blog post.
First there’s the option of static linking i.e. one build that packs all of Qt’s DLLs and your code together in a single .exe file. This hugely simplifies
deployment, but it’s a time consuming process that can be tricky; of course if you distribute large quantities of your software, static linking is definitely something you should try.
But if you’re not yet targeting a couple of millions of PCs (or a similar number
)
then you’re building your Qt app the normal, dynamic way. And that app structure in Qt depends heavily on shared or dynamically loaded libraries; on your deployment PC the Qt installer sets these up for you, but on other PCs you need to do it yourself. You
can either use an installer, for example Qt has a good one, or copy the files
manually.
A good idea here is to find a way to install your Qt app on a vanilla computer with minimal intrusion, because maybe you don’t have administrative or physical access to it, instead perhaps relying on a network share or FTP. For Windows this means no
writing to the registry (once the app is installed, it can use the registry for preferences or similar stuff, but this is about the install process) or create files in “system” locations like C:\Windows etc. For Linux and Macs, it means no fiddling with .conf
files in /etc and no file copying to /usr/lib or similar places.
First step anyway is to build your app in release mode and collect all the needed files together. If you’ve read myearlier
post about distributing a bare-bones Qt app, the files and directory structures used in that post are a good start. Also while it is possible to compile and build a Windows Qt app on Mac, here I’m assuming you’re using a Windows PC for Windows deployment,
a Mac for Mac deployment and a Linux installation for Linux stuff. (Re. Linux: I’m only using/testing Ubuntu and Debian, and on these the Qt installation files are the same, but other distros may differ here.)
The DLL (or .so and .dylib) files that a Qt app needs for successful launch can be divided into 3 flavors:
Qt specific DLLs:
For
Windows, say a Qt widgets app, they are at least
Qt5Core.dll,
Qt5Gui.dlland
Qt5Widgets.dll.
For Linux, they’re
libQt5Core.so.5,
libQt5Gui.so.5and
libQt5Widgets.so.5and
on the Mac they’re
QtCore.framework,
QtGui.frameworkand
QtWidgets.framework.
A “real” Qt app most likely requires some more.
Note: for a typical Qt development installation, the library files/DLLs can be found in two different places, one is in your compiler directory, for example …\mingw48_32\bin, and the other
is a subdirectory of QtCreator. Don’t use the files from the latter place, those DLLs in QtCreator’s subdirectories are for QtCtreator’s own use, it’s a Qt app (of course!). In some cases, like in Linux, the DLLs are identical to the ones in the compiler directory;
in other cases, like for a MinGW-flavored installation of Qt on Windows, they are not (QtCreator is built using Visual Studio and those .dlls do not work for a Qt app built with MinGW!). Instead, always use the library files in your compiler’s …\bin
directory.
A Qt app, like other apps, relies on the OS to load those library files, which means that they must be placed where the OS can find them. On Windows, this means either next to the .exe file in the same directory
or in a directory specified in the search path, for example C:\Windows\System32. On a PC with Qt installed, the DLLs are located by adding the directory to the search path, either by QtCreator when you run your app from it, or by manually invoking
qtenv2.batin
Qt’s compiler’s bin directory.
When copying the DLLs to another PC without Qt installed, usually you don’t want to mess with the search path on other computers, instead placing the DLLs together with the .exe file is probably the best solution.
On Linux, placing the .so files next to the .elf file in the same directory does not cause them to be found/loaded automatically like in Windows; you can add directories to the search paths or ld.so’s .conf
files, but a less intrusive way is using the rpath setting in the .elf file, and that’s what Qt
does. On your development PC with Qt installed, when building your app, QtCreator sets the
rpathon your .elf file so that it points
to the lib subdirectory inside Qt’s installation directory (where the .so files for Qt are located).
This is quite handy when you want to launch your app from Nautilus or Terminal (don’t need any .bat files like in Windows!) but when you later deploy your app to another Linux computer without Qt installed, then that
rpathsetting
is guaranteed to be wrong
and needs to be fixed.
Note: you can get lucky, for example on Ubuntu, there usually is a Qt installed in /usr/lib/i686-linux-gnu or /usr/lib/x86_64-linux-gnu, so your app might run anyway (ld.so, the dynamic linker/loader, gets those paths from the .conf files in /etc/ld.so.conf.d).
But beware of the versioning problem, the Qt supplied by Ubuntu might be too old for your app to launch ok.
For how to fix that
rpathsetting, look at my my
previous post about deploying a bare bones app for Linux.
On Macs also there’s no default loading of .dylibs when they’re placed together with the .elf file. Apple in Leopard (10.5) introduced a rpath
setting similar to the one in Linux. One minor problem is that there’s no
chrpath(or
patchelf)
available for OSX to set the rpath; i.e. it can only be set at link time from QtCreator. And another complication is that the library files are (mostly) placed separately, each in their own directory structure.
All this means, while it’s no problem launching your Qt app from Finder or from Terminal on your dev. Mac with Qt installed, you’re up the creek without a paddle when deploying your Qt app to another Mac with no Qt on it. Since the
rpathcan
not be changed easily, you’ll have to run Apple’s
install_name_toolon your .elf file multiple times, specifying the new path to each
.dylib and framework of Qt it depends on. And for every Qt .dylib/framework that has a dependency on another .dylib/framework, e.g. QtGui.framework depends on QtCore.framework, those needs a whacking with install_name_tool as well.
Thankfully, someone with a brain has written a utility for this called macdeployqt. You run it on your development Mac, I’ve written about in my
previous post.
C++ compiler specific DLLs:
Some MSVC redist installs on a typical Windows PC
While all 3 platforms depends on these kinds of .DLLs, on Linux and Macs it’s presumed that those files (like libstdc++.so.6 or libstdc++.6.dylib) are present and recent enough to work, but on Windows, mostly
because of the variety of compilers, this needs to be addressed when deploying to another PC. The easiest is to copy them together with the Qt specific DLLs, and in my
previous post I show you how.
However, for the Microsoft compiler DLLs, they recommend not just simple copying them (although that works just fine). Instead you should copy and install a vcredist package (can be found in the Qt’s vcredist
subdirectory), thereby installing the MSVC dlls not together with your app, but somewhere within the bowels of C:\Windows.
The reason for this extra step is to give Microsoft an opportunity to update those .dlls if needed, in case they find a bug or security problem in them. This is in theory a good idea, but for me, it also has
during the years meant a couple of early Monday morning calls from customers complaining about my broken app. And discovering that the reason was Microsoft updating their dlls. To be fair, this was not the Visual C++ dlls, two that I can remember were: ATL
security update and an ADO update.
DLLs loaded by Qt itself a.k.a. plugins:
Welcome
to an interesting nook and cranny of Qt deployment, the DLLs that Qt loads by itself! The DLLs mentioned above, they are all standard DLLs loaded by the OS which means you have to know how Windows, Mac and Linux loads library files. But also
if a file is missing, you will get an error, a message box or some other diagnostic message, like “This application has failed to start because Qt5Core.dll was not found.” then you have something to google on.
Qt plugins on the other hand are more sinister in this regard, for many of them when they are missing/not found in the expected place, your Qt app will fail silently
No
error message or diagnostic output, just an app that doesn’t start or exhibits reduced functionality. For example, a Qt Quick app that cannot find the needed QML/QtQuick plugins will instead display an empty white window. Also when trying to find the DLLs
your app depends on, when running a tool like Dependency Walker or
lddon
Linux, the Qt plugin DLLs will not show upbecause these tools only display the normal DLLs requested/imported by the app, and not the plugin DLLs that Qt only knows about. To see them, you need to first launch your app (so that they are loaded into
memory) and then use a tool like ListDLLs for Windows or the
built-in
lsofprogram in Mac and Linux.
Another gotcha re. these plugin DLLs: even though you are super sure you’ve placed them in the correct place, you can still be greeted with “… could not find or load the Qt platform plugin…”
This can happen because a DLL that these guys depend is missing. Since Qt is the loader (and not the OS) you won’t get the usual diagnostic “not found” message. Running Dependency Walker or ldd for Linux on the DLL in question, can be helpful for
debugging these kind of errors.
For example, the Visual Studio-flavored non-OpenGL platform plugin
qwindows.dllneeds
libEGL.dll,
and in Linux
libqxcb.sodepends on
libQt5DBus.so.5and
libxcb.sofor
the X server stuff. Also an additional gotcha: for non-OpenGL MSVC-flavored deployments, that
libEGL.dllfile has be placed not together
with the
qwindows.dllbut together with the other Qt dlls (because while Qt loads the plugin
qwindows.dll,
it’s the OS that loads other files it depends on, like
libEGL.dll).
So how does Qt load these plugins, what are the rules? At start, Qt makes a list of directories where it hopes to find the plugin DLLs. For such a plugin directory to be valid, it has to contain some subdirectories with predetermined names like:
platforms,sqldrivers,imageformats.
These subdirectories are where Qt expects to find the plugins DLLs. It does so by enumerating all files in the subdirectory, looking for matching plugin
keys. When you install Qt, it creates such a plugin directory directly below the compiler, for example
.../clang_64/plugins .../gcc_64/plugins or ...\mingw48_32\plugins. If you look at them, they contain something like 15 different subdirectories. For deploying your app, most likely you only need to copy one or two of those.
The most important plugin type is the
platformssubdirectory. Those DLLs are called platform
plugins and are needed by all Qt apps (even a minuscule Qt app like the bare bones one in my previous post), and the default one is qwindows.dll (libqxcb.so for Linux or libqcocoa.dylib for the Mac). This is Qt’s QPA (Quarter Pounder Advanced™ just
kidding, it stands for Qt Platform Abstraction layer), it’s responsible
for many OS-specific things, for example translating calls like
setWindowState(Qt::WindowMaximized)to Windows/Linux/Mac specific system
calls.
I mentioned Qt doesn’t care about the plugin filenames, only about the subdirectory names, let me give you an example:
The filenames for plugins are immaterial
If I rename qwindows.dll to grapefruit.jpg, Qt will still happily load it as a DLL. Contrast that with for example when Windows wants to load
Qt5Core.dll,
it can be in any directory along the PATH or next to the .exe file for the app, Windows doesn’t really care, as long as the filename is correct. Qt instead fubars if the subdirectory
platformscannot
be found.
Thankfully, for these platform plugins, Qt do display an error message in case they cannot be found. In Windows Qt displays a message box, for Macs and Linux these errors usually can be seen when you launch
your app from Terminal. (True also for the normal DLLs.) So if Qt’s plugins are not deployed correctly, that error message is a good diagnostic, my previous
post shows these errors in more glorious detail.
Let’s look at how Qt’s list of plugin directories are determined at app start, and how you can use these rules for successful app deployment.
Remember that this list specifies the main plugin directory (which is
pluginswhen you install Qt) and that the real McCoys, the plugin
DLLs themselves, are stored in the subdirectories below it.
Actually there are 5 (!) different choices for establishing the plugin directory:
Binary editing of Qt5Core.dll (or libQt5Core.so.5 or QtCore.framework/QtCore):
Hexediting Qt’s plugin path
This is the big wheel approach to plugin lookup, favored by Qt’s installer. When you install Qt on your development PC, the installer patches Qt5Core.dll with the path you specified for your convenience. This means whenever you start Qt apps on your development
machine, the plugins will always be located fine and dandy. (From the point of view of deployment to another PC, this instead could be considered a disservice. Nevermind.)
To see the current path setting (note: for Windows you might need to download Sysinternal’s
strings utility):
Windows: strings Qt5Core.dll | find "qt_plugpath" Linux: strings libQt5Core.so.5 | grep qt_plugpath Macs: strings QtCore.framework/QtCore | grep qt_plugpath
Then if you’re into hex editing yourself, you can apply a new setting for deployment:
Changing to a path more suitable for deployment
You can change to another absolute path, but a relative path works too, it means Qt will use the directory where the .exe file is and append the plugin path to it.
For example, assume you’ve placed your Qt app in the directory
C:\CompanyApps. Then
if you’ve hex edited
Qt5Core.dllas above and copied it into \CompanyApps as well, then Qt expects to find
qwindows.dllin
the directory
C:\CompanyApps\plugins\platforms.
When I tested on Windows with a relative path I had to prefix it with C: which obviously doesn’t work on Linux and Macs. So while this is a viable method for plugin deployment, I suggest you leave this option
to the big wheels
Note: remember if you’re running your app in Debug mode then the settings in
Qt5Cored.dllwill
apply,not
Qt5Core.dll.
Setting the environment variable QT_PLUGIN_PATH
:
Using an environment variable might be an easier option than hex editing Qt5Core.dll, and the effect will be the same, for example:set QT_PLUGIN_PATH=plugins
will perform the same feat as above, Qt will look for
qwindows.dllin
C:\CompanyApps\plugins\platforms.
Of course you can also set an absolute path this way. And if you want a bonanza of plugins directories, you can append additional paths separated with ; (or : in Linux and Macs).
Specifying the plugin path in your code:
Adding the plugin path in main()
You can also specify a plugin path in your code, but since Qt loads the plugins when QApplication is constructed, your window of opportunity is to do it before QApplication’s constructor is called.
The call above is a 3rd alternative for telling Qt to look for
qwindows.dllin
C:\CompanyApps\plugins\platforms(using
the same example as above).
Creating a qt.conf
file:
This is a popular method of setting up a path to the plugins, used for example by the QtCreator app and the macdeployqtutility on Macs. Create a text file, like this:
[Paths] Plugins=plugins
If such a file exists in the same directory as the app’s .exe file, Qt will read it and add the
plugins=path
to its list of plugin directories. The example above accomplishes the same thing as in the previous examples, it causes Qt look for
qwindows.dllin
...\plugins\platforms.
One caveat here if you’re on Windows: backslashes in the
Plugins=setting don’t work,
you should use Linux-style forward slashes.
Using the default directory:
This is by far the favorite method for setting up the plugin directory, since it’s provided for free by QtHow does this work? Well, when your app starts, Qt as a freebie adds the directory where your app’s .exe file is located to its list of plugin directories.
Note that this is not the same as the examples above, in those we instructed Qt to look for plugins in
C:\CompanyApps\pluginsbut
this default setting tells Qt to look for plugins in
C:\CompanyApps. I.e. an equivalent env. variable setting would be:
set QT_PLUGIN_PATH=.
or an equivalent
qt.conffile would look like this:
[Paths] Plugins=.
So if we take the example above again; you’ve deployed your app to the directory
C:\CompanyApps.
This means that Qt automatically will look for
qwindows.dllin
C:\CompanyApps\platforms.
For example, if you look at my previous post you’ll see that for deployment of that bare bones app,
I always go for this option, i.e. placing the
platformsdirectory directly below the main directory.
Q: “Then why does Qt Creator go through the trouble of creating a
qt.conffile
for itself, when it suffices just to copy the plugin subdirectories into the app’s directory?”
One reason could be to reduce litter in the app’s main directory, if we look at Qt Creator’s
qt.conffile,
it has the line
Plugins=plugins(same as in our examples above). Since it has 7 different plugin subdirectories (9 in Linux) it makes
sense to stash away all those subdirectories in a separate
pluginsdirectory.
Another reason for creating a qt.conf file:
macdeployqtcreates one, because on the
Mac there’s an app bundle standard that plugins should reside in their own directory called
PlugIns.
Remarks: if you use a
qt.conffile, it supersedes the other settings, so if you make
a spelling error in it, that can cause plugin loading to fail. Also the last two methods (the most popular ones) are currently slightly more brittle due to an obscure
bug, for example if you call QStyleFactory::keys() before QApplication a(argc, argv) in your main.cpp, this preempts the path to the .exe file and a path in
qt.confto
be setup as eligible plugin directories.
Finally, if you’re still running into plugin loading problems, you can turn on a trace of the plugin loading process, by setting the environment variable
QT_DEBUG_PLUGINSto
a nonzero value, like this:
SET QT_DEBUG_PLUGINS=1
(for Linux and Macs instead use
export), and then launch your app from the CMD/Terminal
window. For Linux and Macs you’ll see lines something like “QFactoryLoader::QFactoryLoader() checking….” displayed in Terminal, but in Windows Qt routes the output to the OutputDebugString() API, so nothing will be displayed in the CMD window. The output can
be seen using Visual Studio or Qt Creator, which isn’t very helpful if you’re experiencing the plugin problems on a non-development PC. An alternative is to download a utility: DbgView
from Sysinternals and open it before you launch your app you’ll be fine.
Bonus contents if you are crazy and not happy with *only* 5 choices:
Remember I said the Qt plugin subdirectory names likeplatforms,sqldrivers,imageformatsare
hardwired in Qt’s plugin loader? I lied, you can actually change
platformsto some other, even an absolute pathname. Note that this
is different from the previous 5 choices, since they are for specifying the
pluginsmain directory (where the subdirectories are),
while this setting is for changing only the
platformsname or location (the settings are independent from each other). Why this is
useful? Really don’t know, but I’m guessing for debugging/testing. Also note that this option is not available for Qt Console apps, only Quick- and Widgets-flavored ones.
Say you want to change to instead use the subdirectory
test, then you can either
set/export an environment variable:
set QT_QPA_PLUGIN_PATH=test
or give a command line argument when launching your app:
YourQtApp -platformpluginpath test
Note that if this is a relative path (like in my example) then it’s relative to the app’s .exe file, so for a more convoluted case, if you’re using a
qt.conffile
that overrides the default plugins directory
.(where your .exe file is located), instead setting it to
plugins,
then if
testis a subdirectory in
plugins,
you would instead have to type:
YourQtApp -platformpluginpath plugins/test
Looking at other Qt apps:
Finally, to understand more of the deployment process, I think it’s useful to look at other (than your own) Qt apps; I’m thinking of one Qt app which is installedin your Qt folder: QtCreator. Besides creating the version specific (like
5.3) directory structure where the compiler files
are, Qt’s installer also creates the
Toolsdirectory which contains QtCreator. On the Mac there is no Tools subdirectory, instead you’ll
find a Qt Creator.app (which is a directory, you open it with a rightclick and Show Package Contents in Finder).
QtCreator is packaged ready to deploy, i.e. you can copy it (the directory or in the Mac case, the app) to another computer and it will start just fine. (For
Windows, you might need to install the vcredist_msvc2010 runtime located in the QtCreator’s lib subdirectory.) If you copy it to a PC without a Qt installation, it might not compile and build apps, but it would still function well as a text/code editor
So let’s look on how it solves its deployment, first the normal DLLs:
In Windows, all the needed DLLs are placed together with
qtcreator.exein the same directory (except for the compiler specific DLLs,
which is installed using the vcredist package I mentioned earlier).
In Linux, the .so files are in a neighboring subdirectory:
../lib/qtcreator, and for the .so files to be found by the ld.so loader,
the .elf file has a custom
RPATH/chrpathsetting:
"$ORIGIN/../lib/qtcreator".
In Macs, all the .dylib and framework files QtCreator needs are included in the app bundle (if you do
otool -Lon QtCreator’s .elf file
in the MacOS folder, you’ll see for example
@loader_path/../Frameworks/QtCore.framework....). It’s look quite similar (but not exactly
the same) as when you run the utility
macdeployqton your own Qt app’s folder.
Then the plugin DLLs, how are they located? Well, if we start by looking at
Qt5Core.dll,
a
stringssearch of it finds
"qt_plugpath=c:/work/build/PADDING/plugins"(on
Linux and Mac it’s more or less the same setting).
Obviously there’s no “/work/build” directory, so clearly the option of using
Qt5Core.dllfor
specifying the plugin directory is unused by QtCreator.
(BTW, this is one of the reasons why this Qt5Core.dll is not replaceable with the Qt5Core.dll in the compiler directory, because the
qt_plugpathin
that one is used and expected to be valid.)
So, QtCreator does not set any environment variables and does not call
addLibraryPath()in
main.cpp, nor is the default directory option used. Instead (as I’ve already mentioned above) QtCreator has a
qt.conffile to specify
its plugin directory, using the relative path
plugins.
If you want to experiment, momentarily rename or move away the qt.conf file, and then try to start QtCreator. You’ll see that infamous message “… could not
find or load the Qt plugin …. “, same for any other Qt app
Don’t
forget to restore the qt.conf file!
相关文章推荐
- Qt5 发布的exe应用程序Windows下无法执行的问题解决方案
- 安装C++ GUI Qt 3 运行程序无法找到qt-mtnc321.dll
- QT程序发布的一个问题:无法定位程序输入点与动态链接库QtCore4.dll
- QT编译发布程序后报错如缺少dll、“应用程序无法正常启动(0xc000007b)”的可能解决方法
- Qt发布错误:无法定位程序输入点于动态链接库QtCore5.dll
- C#.winform使用sqlite发布时提示无法找到SQLite.Interop.dll的问题
- Windows下如何使用QT编写dll程序
- 安装windows组件 提示 无法加载安装安装程序:Wbemupgd.dll
- 网站发布后,在IIS中浏览提示:无法找到该页...404错误。
- 电脑问题——“windows无法找到c:/windows/rundll32.exe”
- 网站发布后,在IIS中浏览提示:无法找到该页...404错误。
- 关于在windows下部署发布QT程序的总结
- 关于 hal.dll无法找到 windowXP启动
- 终于解决kdevelop 无法找到qt头文件的方法了
- 关于在windows下部署发布QT程序的总结
- QT程序发布的一个问题:无法定位程序输入点与动态链接库QtCore4.dll
- WebService 发布不成功,显示无法找到该页错误 404的解决方法
- [转]小问题: windows组件调用失败,无法加载安装安装程序:Wbemupgd.dll
- [VB.NET]安装完office2003后,无法找到com库文件Interop.Excel.dll?
- windows组件调用失败,无法加载安装安装程序:Wbemupgd.dll