Deploying Qt or how to avoid “could not find or load the Qt platform plugin”

(转自:http://www.tripleboot.org/?p=138

Once you’ve built your first Qt program, have you tried it on another PC?
(Post updated and simplified! Thanks to JKSH on the Qt Project forums.)
Maybe you’ve gotten past .DLL errors, instead you’re stuck on errors like these?

Could not find or load the Qt platform plugin "windows"

If you’ve experienced this, then this blog post is for you :-)

 
Failed to load platform plugin "xcb"

(Start your app in Terminal to see this)

Failed to load platform plugin "cocoa"

(Same here, Finder only says “App quit unexpectedly”, launch your app in Terminal to see this)

(Want to skip the tourist talk? Jump to the rest of the post.)

If you look at newer languages like Google’s Go, you’ll find an Everything and the Kitchen Sink™-flavored approach to deployment. After you’ve written and debugged a Go program, you issue the go build command. The result is an .EXE file with minimal dependencies on the DLLs, in Windows for example it’s just the usual suspects like KERNEL32.DLL etc. People sometimes complain though, because even a simple ‘Hello World’ app weighs in to an approx. 2MB .exe file. But deployment problems are more or less nonexistent.

Qt has (as you’ve probably discovered) the complete opposite design. From things like .h files that are designed this way (a humongous file like Windows.h is frowned upon) to the delegation of .DLLs that Qt uses for plugins, platform independency etc. Partially this stems from the early 90’s when Qt was initially designed (in those days, deploying a 2MB .exe could constitute a career-limiting move) but probably mostly because it supports so many different architectures and OS’es.

Now, to simplify deployment of Qt apps to other PCs, you can rebuild all or parts of Qt statically. In some environments that makes sense, but I think in general you’re better off following this dynamic library approach.


(Updated November 16, 2014 for Qt 5.4)
First let’s look at the stuff you get when you download and install Qt. You can use the online or the offline installer. To simplify this blog post, let’s focus on the online installer. It will prompt you for the main Qt install directory, the default is ~/Qt for Mac and Linux and C:Qt for Windows systems. The offline installer instead will default to a version specific directory, for Qt 5.4.0 it will prompt you with something like C:QtQt5.4.0 for MinGW on Windows. The files installed will be the same anyway, let’s assume you go with the online installer and accept the default directory name Qt. Inside that directory will be a couple of subdirectories, like Examples, Docs and Licenses. On Windows and Linux there will be a subdirectory called Tools which contains Qt Creator, Qt’s IDE (on the Mac there is no Tools subdirectory, instead there’s a Qt Creator.app).

Important: that Tools subdirectory contains a version of Qt deployed for Qt Creator; copying those files from the Tools directory will give you Bad Karma because they are customized for Qt Creator and *not* for your apps. Instead, look in the other directory created, for Qt 5.4 it’s 5.4; it contains a subdirectory named after the compiler you selected, like clang_64, gcc_64, mingw482_32, msvc2013 etc., that’s where you’ll find the compiler specific Qt files which can be distributed safely to other computers. I’ll be referring to that one as the compiler directory in this blog post. (And inside it are the important bin, lib and plugins subdirectories, more on that later.)

So let’s start by looking at deployment of an absolute bare bones app, let’s call it HelloQt. In Qt Creator, select a new Project, Applications and a Qt Widgets application. Click through and accept all the default choices. Once you’re in the project, switch it to Release mode. This is to simplify deployment, and if you’re using Visual Studio as your compiler, Microsoft disallows copying any of the debug .DLLs to another computer.
Also: apps compiled in release mode with the MingGW compiler for Windows, actually will tell you more than when they’re compiled in debug mode, for example that message about not finding the Qt platform plugin which this blog post is all about, will only be displayed in release mode.

Right now don’t edit or add any code, for our purposes an empty app window will do just fine. Just build our fancy app in Qt Creator, then make a test directory on another computer that has no Qt installed. Depending on your OS and compiler, the files you then need to copy vary slightly:

    • Windows compilers:

      (update Nov. 16 2014: What about Visual Studio 2015, does it work with Qt? Haven’t tested yet, but I’m guessing it will do just fine)

      (note: the screen dumps are still from Qt 5.3, not yet from Qt 5.4, so the icu*.dlls should instead be icudt53.dll etc. But you’ll get the idea anyway I think…)

        • MinGW 32-bit compiler

          Bare bones MinGW deployment

          Bare bones MinGW deployment

          Bare bones MinGW platforms directory

          Bare bones MinGW platforms directory


          The qwindows.dll file in the platforms directory above, you’ll find and can copy from compiler directorypluginsplatforms, the other files you’ll find in compiler directoryin.

          (What’s that compiler directory you ask? Look in the text above for an explanation. For MinGW installed with the online installer the default directory is C:Qt5.4mingw482_32)

          The HelloQt app should now run fine on the other Windows computer.
           

        • Visual Studio 2013 32-bit and 64-bit compilers:

          Bare bones VS2013 64-bit deployment

          Bare bones VS2013 32-bit and 64-bit deployment

           
          Bare bones VS2013 platforms directory

          Bare bones 32-bit and 64-bit platforms directory

          The qwindows.dll file is in compiler directorypluginsplatforms and the other files you’ll find in compiler directoryin. Let’s not forget the 2 compiler specific files msvcr120.dll and msvcp120.dll, I usually copy them from C:WindowsSysWOW64 on my development PC.

          For 64-bit app deployment the file setup above is identical, but beware: the 2 compiler files msvcr120.dll and msvcp120.dll you instead find in C:WindowsSystem32. The HelloQt app should now run equally well on the other computer.

          Again: note that the 32-bit MSVC DLL files are in SysWOW64 and the 64-bit files are in System32. Makes perfect sense, agreed?

          (update Nov. 16, 2014:) Q: “No, it does not make perfect sense, please enlighten me, o great guru”
          <history_rant> In the beginning there was Windows 1.0, it had a C:Windows directory, inside it was a System subdirectory and there was much rejoicing. Then a software called Chicago a.k.a. Windows 95 was released upon the world. It supported 32-bit Windows apps, those apps required 32-bit flavored infrastructure like DLLs and drivers, and some of those files were identically named as their 16-bit siblings. Solution: put those files in another System subdirectory and call that (surprise!) System32. All was well again and rejoicing resumed.
          A new century and 64-bit computing arrived. The naive among us expected the creation of a 3rd subdirectory called System64, for housing the new fancy 64-bit Windows infrastructure. But alas, it was not to be :-( Because a fear had spread upon the land, a fear that System32 had become too popular and too ingrained. The belief was that the necessary migration to System64 would cause intolerable pain and suffering and perhaps taint the perceived quality of the Windows product. Succumbing to this fear, it was decided that for all 64-bit Windows releases, System32 was to be the home for the 64-bit infrastructure and the old (32-bit) content of System32 was instead to be ignominiously shuffled away into a new subdirectory called SysWOW64. Thus, it was believed, 64-bit Windows should be able to accommodate even those developers that wanted to ascend to 64-bit computing but had fumbled and put hardwired strings like “System32″ into their apps. (BTW, a similar kind of decision was also taken for C:Program Files, so that it would contain the 64-bit apps and 32-bit apps would instead be stored in C:Program Files (x86).) And that’s the story how we ended up with 32-bit DLLs in SysWOW64 and 64-bit DLLs in System32.
          Today, more than 10 years later, I think giving in to that fear was a humongous mistake. Until all 32-bit Windows installations are gone, every day some developer will have to think and spend extra time deciding which directory is correct for picking up the compiler files and similar stuff. If a System64 directory had been created there would be less confusion. </history_rant>

          Q: “I copied the msvcr120.dll and msvcp120.dll files as you said, why do I get error 0xc000007b when I try to launch my app on the other computer?”
          This error occurs when a 64-bit app requests a DLL and a 32-bit version of it is incorrectly loaded, or the other way around, i.e. a 32-bit app loads by mistake a 64-bit DLL. Usually this is because you copied msvcr120.dll and/or msvcp120.dll from the wrong directory (either C:WindowsSystem32 or C:WindowsSysWOW64, also see my rant above).

          Q: “I copied everything ok, but when I try to launch I get a dialog box: “not a valid Win32 application” why?”
          If the other computer has Windows XP or Windows Server 2003 you’ll get this error. To get around it, you need to add a linker setting for your project in Qt Creator, I’ll show you how in the next blog post about XP/2k3 deployment.
           

        • Visual Studio 2013 32-bit and 64-bit OpenGL compilers:

          MSVC 2013 OpenGL barebones deployment

          Bare bones VS2013 OpenGL 32-bit and 64-bit deployment

           
          MSVC 2013 OpenGL barebones deployment platforms directory

          Bare bones VS2013 OpenGL 32-bit and 64-bit platform directory

          This deployment is almost identical to the non-OpenGL versions above, but slightly easier since there are no libEGL.dll and libGLESv2.dll dependencies. So the qwindows.dll file is in compiler directorypluginsplatforms and the other files you’ll find in compiler directoryin. And don’t forget the two compiler specific files msvcr120.dll and msvcp120.dll.
           

        • Visual Studio 2012 32-bit OpenGL compiler:

          Bare bones VS2012 32-bit OpenGL deployment

          Bare bones VS2012 32-bit OpenGL deployment

           
          Bare bones VS2012 32-bit OpenGL platform directory

          Bare bones VS2012 32-bit OpenGL platform directory

          The qwindows.dll file is in compiler directorypluginsplatforms and the other files you’ll find in compiler directoryin. Note that the two compiler specific files in this case are msvcr110.dll and msvcp110.dll.
           

      • Visual Studio 2010 32-bit compiler:

        I have to confess to some laziness here, I haven’t tried recently with VS2010. But it should be the almost exactly as the VS2012 deployment above, except that the compiler specific DLLs are instead msvcr100.dll and msvcp100.dll. Good news: deploying apps built with this compiler to Windows XP or Windows Server 2003 presents no problems.
         

    • Linux GCC 32-bit and 64-bit compilers:

      Debian/Ubuntu GCC bare bones deployment files

      Debian/Ubuntu GCC bare bones deployment files


      Debian/Ubuntu GCC bare bones deployment, platform directory

      Debian/Ubuntu GCC bare bones deployment, platform directory


      Here the platform file is called libqxcb.so, it can be found in compiler directory/plugins/platforms. The other files are in the compiler directory/lib directory (note: not the bin directory as on Windows above). There are no compiler specific .so files, it’s assumed the Linux system you’re targeting is up to scratch re. the libc.so, libgcc_s.so etc files. I suppose if the other Linux is really old this could be a showstopper, I haven’t looked into that possible malaise yet.

      Note that the .so files in the /lib subdirectories are installed by the Qt installer in 4 incarnations: 3 symbolic links and 1 real McCoy, e.g. libQt5Core.so, libQt5Core.so.5 and libQt5Core.so.5.4 are symbolic links to the “real” file libQt5Core.so.5.4.0.
      However, when you list HelloQt’s DLL dependencies, for example typing "ldd HelloQt" in Terminal, you’ll see that the requested .so files are suffixed with just .5, when I copy the files I also rename the real McCoy file from xxx.5.4.0 to xxx.5 and toss the 3 symbolic chaps. (That’s why it’s only one of each above in the screen dumps.) This keeps the no. of files down, also sometimes symbolic links can become roadkill during transit, if you’re zipping them or copying via SMB to a Windows server etc. But you can of course equally well go ahead and copy all 4 of them.

      Update: in Qt 5.4, I noticed that the 3 libicu*.so Unicode files now are installed in 2 incarnations, one *.so.53 which is the symbolic link (the one HelloQt looks for) and the *.so.53.1 which is the real thing. So we’re applying the same algorithm here, copied and renamed the 3 real files and skipped the symbolic links.

       
      When you copy the files shown above to another Linux computer, if you try to launch the HelloQt app you’ll most likely get this error:
      Forgot chrpath

      (On Ubuntu systems the app might run anyway because a fairly recent Qt is included in their distro, more on that below.)
      The reason for this is that the .exe/ELF file is built to look for Qt’s .so files assuming the same library path to them as on your development machine. Even though we’ve copied all the needed .so files (and the platform subdirectory) into the same directory as our app .exe/ELF file, those .so files are ignored in Linux. But we would like to have the same behavior as on Windows; i.e. that Linux when loading the .so files also looks for them in the same directory as the .exe/ELF file is in.
      There is a way to accomplish this, by editing that pre-wired path setting, actually it’s called the RPATH setting and you can choose to make that change either A) when building the app or B) as a command in Terminal after the build (or on existing .exe/ELF files).

      A) When building the the app: Qt (actually the linker) normally sets the RPATH just pointing to the .so files where Qt’s installer put them (for example in my case /home/henry/Qt/5.4/gcc_64/lib) which of course is fine and dandy for your development machine but less so for the other Linux PC.
      However we can tweak that setting by adding a line to our project’s .pro file (I usually put it at the end of my .pro file):

      QMAKE_LFLAGS += -Wl,-rpath,"'$$ORIGIN'"

      What we want is to insert the magic word $ORIGIN as the first RPATH setting, this will cause Linux to look for .so files to load in the same directory as the .exe/ELF file. (The extra decoration "'$...'" is needed for surviving the heavy munging during the build process before arriving at the linker.)
      Actually we can equally well use “.” as an RPATH (i.e. QMAKE_LFLAGS += -Wl,-rpath,"." this will perform the same feat as $ORIGIN) but the docs advise us to use $ORIGIN, so $ORIGIN it is.
      (Note: there are a couple of other .pro file flag commands available for this, for example: QMAKE_RPATHDIR += ":'$$ORIGIN'" but I prefer QMAKE_LFLAGS += ... because it causes $ORIGIN to appear as the first RPATH.)

      B) A command in Terminal: in typical Linux fashion there’s also a utility for setting RPATHs: chrpath, which you can install and run like this:

      sudo apt-get install chrpath
      chrpath -r $ORIGIN HelloQt
      

      (replace apt-get with the download command of your favorite distro if needed)

      The $ORIGIN ( is needed for quoting the $) keyword means the same as above: look for .so files in the same directory first, in other words, emulate Windows .DLL lookup behavior. Also here you can use "chrpath -r . HelloQt" but the docs (as I mentioned above) advises against it.

      Note: we only need to apply chrpath on our main .exe/ELF file, Qt’s .so files already have their RPATHs set to $ORIGIN, i.e. they expect to find each other in the same directory.

      BTW, you don’t need to install chrpath on the other PC, you can do that on your development machine, i.e. prepare the .elf file before shipping (unless of course you instead opted for that extra QMAKE_LFLAGS… line in your .pro file).

      Q: “Not correct, Qt plugins/platforms .so files have their RPATHs set to $ORIGIN/../../lib, not just only $ORIGIN”
      Indeed I’ve seen that, while the .so files in the Qt’s lib directory have $ORIGIN, all the .so files in the plugins directory are wired differently. Note that those .so files are loaded by Qt itself and not by Linux (more on that in an upcoming blog post), so I suspect the RPATH setting is irrelevant anyway. Matter of fact, I tested this:

      cd platforms
      chrpath -r grapefruit libqxcb.so
      

      HelloQt started fine in spite of not having any grapefruit directory :-)

      Q: “But on my Ubuntu machine HelloQt runs anyway, don’t need chrpath!”
      Yes, that’s because Ubuntu comes pre-installed with Qt library files. For example, Ubuntu 13.10 comes with Qt 5.0.2. It’s pretty neat but comes with one danger: what happens if you rely on a Qt feature that was introduced after 5.0.2, like SerialPort? You’ll get an error: “libQt5SerialPort.so.5″ not found, even if you do copy that .so file from your Qt machine. To refrain from diving into one of Dante’s nine “DLL Hells”, I suggest always stick to the plan of applying chrpath to your apps.

      Update: User sunsina on the Qt Project forums suggested a more sophisticated deployment approach: put the Qt’s .so files in a subdirectory called qtlibs:
      (Note: picture isn’t updated yet to Qt version 5.4)

      Debian alternate Qt installation

      Debian (or Ubuntu) alternate Qt installation


      To get this setup up and running, we just need to apply a different chrpath setting to our .elf file:
      chrpath -r ./qtlibs HelloQt
      

      It’s a good point, just because Windows looks for DLLs in the current directory by default, that doesn’t mean we have to go for the same approach here.
       

  • Mac clang compiler:

    The algorithm we’ve used above for Windows and Linux, to copy the executable file and the needed .dlls together and making sure no mixing of 32 and 64-bit flavored files occurs; on the Mac that’s regarded as a clueless all thumbs approach to app deployment. To paraphrase Obi-Wan speaking about his light saber: “not as clumsy or random as a simple app directory, the app bundle is an elegant weapon for a more civilized age.” And it’s hard to argue, the app bundle is a great invention, installing and uninstalling apps couldn’t be simpler.

    So, when you build your app with QtCreator you’ll get an app bundle, do a “Show Package Contents” in Finder, open the Contents folder to see the bundle in all its glory:

    App contents before macdeployqt

    App contents before macdeployqt

    Now, if you copy the app bundle (HelloQt.app) to another Mac and try to launch it, it will fail. Right now it’s mostly an empty shell, none of Qt’s DLLs (frameworks and dylibs) are present. The executable file, for example, is set to load QtCore.framework and the other frameworks from where you installed Qt.
    So while the app bundle is fine and dandy on your development machine, it clearly needs some more stuffing before you can deploy it to another Mac. I used to do this manually until I read on Qt’s website about a handy utility included in Qt’s installation that helps you with this, it’s called macdeployqt. You can find it in your ../clang_64/bin directory.
    Here’s an example, we’ll run it on our HelloQt app, using Terminal:

    Using macdeployqt from Terminal

    Using macdeployqt from Terminal

    It’s designed according to the paradigm “no news is good news”, i.e. if you don’t see any error messages, it all went well and the size of your app bundle should have grown. In the case of the HelloQt app from about 100 kbytes to 20 MBytes. Let’s open the Contents folder again:

    App contents after macdeployqt

    App contents after macdeployqt

    Now, if you copy this 20MB bundle to another Mac, it should run just fine. macdeployqt does a lot of install_name_tool invocations and other shuffling that (believe me!) you should be very glad not to have to do yourself.

    For deployment problems, the first tool you need to learn on the Mac is otool (the devs who wrote it were watching Lawrence of Arabia with Peter O’Toole at the time, no just kidding!). Example: to see what .dylibs our app needs, do:
    otool -L .../HelloQt.app/Contents/MacOS/HelloQt

    Note: once you’ve run macdeployqt on your app bundle, don’t reopen that project in QtCreator!
    If you do, you’ll see these kind of messages when you build and launch your app again:

    QtCreator does *not* like projects that macdeployqt has visited

    QtCreator does *not* like projects that macdeployqt has visited

    The cure is easy: just delete the build folder (which contains the app bundle), then you can start working on your app in QtCreator again.
     

  • Android and iOS:

    Interesting new Qt platforms but I haven’t gone there yet! I’ll update this blog post when I do.

So far I’ve covered how to deploy a bare bones app. Once past this hurdle, deploying real apps that depend on Qt libraries like ODBC, MySql, Sensors, QtQuick etc. follows the same approach.

Next blog post: deploying to Windows XP and Windows Server 2003.

Update: now when you know a bit more on how to deploy Qt apps, I’ve written a blog post on why the deployment works the way I’ve written about above.

原文地址:https://www.cnblogs.com/FindSelf/p/4682039.html