Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Installation and Deployment
  4. Qt 5.0 and 'failed to load platform plugin "cocoa"'
Forum Updated to NodeBB v4.3 + New Features

Qt 5.0 and 'failed to load platform plugin "cocoa"'

Scheduled Pinned Locked Moved Installation and Deployment
10 Posts 6 Posters 26.8k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • P Offline
    P Offline
    paulheckbert
    wrote on last edited by
    #1

    I'm on Mac OS 10.8.3. After porting my Qt app from Qt 4.4 to Qt 5.0, I was getting the following fatal error immediately when I would create a Mac bundle and then run the bundle app:

    Failed to load platform plugin "cocoa"

    To debug this, I tried reading http://qt-project.org/doc/qt-5.0/qtdoc/deployment-mac.html and related pages, but found them only partially helpful. I also tried macdeployqt but couldn't get it to work. All of this needs much better documentation.

    Here is what I did to get my app to work. Using

    @
    export DYLD_PRINT_LIBRARIES=1
    @

    before running my app, I found that the library causing the above error was libqcocoa.dylib. Typically one is able to find all dylib and framework dependencies of an executable using the "otool -L" command, recursively following the graph of dependencies, but libqcocoa is not found this way (perhaps because it's a plugin?). But if you run "strings" on QtCore, you'll find references to libqcocoa there. Note that simple Qt apps don't need libqcocoa, but mine did. So I need to add this library to my bundle.

    If qtdir is the dir where Qt 5.0 is installed (in my case it was /Users/paul/more_stuff/qt5.0.0/5.0.0/clang_64) and appdir is the dir for the app bundle being put together (in my case it was name.app) then the cause of the above error was that Qt's runtime library was looking for qtdir/plugins/platforms/libqcocoa.dylib but I want to eliminate all dependencies on qtdir, which exists only on my build machine. I need to make my app more self-contained.

    First, I changed my C++ code to replace the line

    @
    QApplication app(argc, argv);
    @

    with

    @
    QDir dir(argv[0]); // e.g. appdir/Contents/MacOS/appname
    assert(dir.cdUp());
    assert(dir.cdUp());
    assert(dir.cd("PlugIns")); // e.g. appdir/Contents/PlugIns
    QCoreApplication::setLibraryPaths(QStringList(dir.absolutePath()));
    printf("after change, libraryPaths=(%s)\n", QCoreApplication::libraryPaths().join(",").toUtf8().data());
    QApplication app(argc, argv);
    @

    This changes the plugin directory to be relative to appdir (no longer relative to qtdir). Note that it must be done before the QApplication constructor, because that is where the link error above was occuring.

    I also needed to copy libqcocoa and its extra dependencies into my bundle and patch up the identities and reference paths in the dylibs. otool -L is handy for figuring out these dependencies. In my case, there was only two dependencies due to plugins: libqcocoa.dylib and QtPrintSupport.framework. The commands came down to the following:

    @

    install libqcocoa library

    mkdir -p $appdir/Contents/PlugIns/platforms
    cp $qtdir/plugins/platforms/libqcocoa.dylib $appdir/Contents/PlugIns/platforms

    fix its identity and references to others

    install_name_tool -id @executable_path/../PlugIns/platforms/libqcocoa.dylib $appdir/Contents/PlugIns/platforms/libqcocoa.dylib
    install_name_tool -change $qtdir/lib/QtPrintSupport.framework/Versions/5/QtPrintSupport @executable_path/../Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport $appdir/Contents/PlugIns/platforms/libqcocoa.dylib
    install_name_tool -change $qtdir/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets $appdir/Contents/PlugIns/platforms/libqcocoa.dylib
    install_name_tool -change $qtdir/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui $appdir/Contents/PlugIns/platforms/libqcocoa.dylib
    install_name_tool -change $qtdir/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore $appdir/Contents/PlugIns/platforms/libqcocoa.dylib

    install QtPrintSupport framework

    cp -r $qtdir/lib/QtPrintSupport.framework $appdir/Contents/Frameworks

    fix its identity and references to others

    install_name_tool -id @executable_path/../Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport $appdir/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
    install_name_tool -change $qtdir/lib/QtWidgets.framework/Versions/5/QtWidgets @executable_path/../Frameworks/QtWidgets.framework/Versions/5/QtWidgets $appdir/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
    install_name_tool -change $qtdir/lib/QtGui.framework/Versions/5/QtGui @executable_path/../Frameworks/QtGui.framework/Versions/5/QtGui $appdir/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
    install_name_tool -change $qtdir/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore $appdir/Contents/Frameworks/QtPrintSupport.framework/Versions/5/QtPrintSupport
    @

    Piece of cake, right? :-)

    This worked for me.

    Small remaining puzzles:

    1. why does Qt load libqcocoa as a plugin?
    2. is there a way, without running the app, to get a list of the paths to the plugins it will load?
    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      For number 1, it's because it's the implementation of Qt Abstract Platform for OS X (there is one such plugin for each support system)

      For number 2, I don't know, since plugins are loaded at run time

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0
      • Y Offline
        Y Offline
        yuichi
        wrote on last edited by
        #3

        Hi paulheckbert,
        Thanks.

        I can confirm "PyQt5 + Qt5.0.2 + Python3.3 + py2app" works fine on your way.
        They were showing same trouble.
        Failed to load platform plugin “cocoa”

        Py2app doesn't include plugins automatically.
        So I copied it to .app manually.
        However, the plugins cause trouble because it doesn't have correct reference to the object which included to .app.

        I wrote these scripts in my setup.py to configure reference.
        Now I can deploy my pyqt app.
        I hope my post help someone who have same trouble :)

        @
        # (1) remove build files

        # (2)  issue setup command
        
        # (3) copy plugin 
        #plugin
        print("copy plugins")
        os.system("cp -r plugins dist/test.app/Contents/PlugIns")
        os.system("cp qt.conf dist/test.app/Contents/Resources/qt.conf") 
        
        # (4) correct dylib references
        
        appPath = "PATH_TO_YOUR_APP"
        qtPath = "PATH_TO_QT_LIB"
        pythonPath = "PATH_TO_PYTHON"
        
        def iid(dylib):
            command = "install_name_tool -id @executable_path/../PlugIns/{dylib} {appPath}/Contents/PlugIns/{dylib}".format(dylib=dylib, appPath=appPath)
            os.system(command)
        
        def icPython(dylib):
            command = "install_name_tool -change {pythonPath}/Python.framework/Versions/3.3/Python @executable_path/../Frameworks/Python.framework/Versions/3.3/Python {appPath}/Contents/PlugIns/{dylib}".format(dylib=dylib, appPath=appPath, pythonPath=pythonPath)
            os.system(command)
            
        def icCore(dylib):
            command = "install_name_tool -change {qtPath}/lib/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/Versions/5/QtCore {appPath}/Contents/PlugIns/{dylib}".format(dylib=dylib, appPath=appPath, qtPath=qtPath)
            os.system(command)
        
        ....
        
        def update(dylib):
            iid(dylib)
            icPython(dylib)
            icCore(dylib)
            ....
        
        #accessible
        print("# update accessible")
        update("accessible/libqtaccessiblequick.dylib")
        update("accessible/libqtaccessiblewidgets.dylib")
        
        #bearer
        print("# update bearer")
        update("bearer/libqcorewlanbearer.dylib")
        ....
        
        #platform
        print("# update platforms")
        update("platforms/libqcocoa.dylib")   ## <-- you need it
        update("platforms/libqminimal.dylib")
        
        ......
        

        @

        I think you can use same method to PyQt4 trouble.

        1 Reply Last reply
        0
        • Y Offline
          Y Offline
          yuichi
          wrote on last edited by
          #4

          I forgot to write a important thing.
          you also need to configure qt library path before creating QApplication Instance.
          It is almost same to pure Qt5's way.

          @if deploy:
          print("DEPLOY")
          for path in QApplication.libraryPaths():
          QApplication.removeLibraryPath(path)

          filePath = os.path.dirname(os.path.abspath( __file__ )) 
          # abspath returns "APP_DIR/Contents/Resouces". This isn't same to C++ app.
          fileDir = QDir(filePath)
          fileDir.cdUp()
          fileDir.cd("PlugIns")
          appPath = fileDir.absolutePath()
          QApplication.addLibraryPath(str(appPath))
          

          print("INIT: " + str(QApplication.libraryPaths()))
          app = QApplication(sys.argv)
          @

          If you didn't do it, your app will crash.
          Because, it can't find "cocoa" plugin.

          1 Reply Last reply
          0
          • S Offline
            S Offline
            Stunt
            wrote on last edited by
            #5

            Thank you so much paulheckbert :D

            1 Reply Last reply
            0
            • B Offline
              B Offline
              bootchk
              wrote on last edited by
              #6

              I also experienced this, on my dev machine (where Qt is installed), when in Xcode I turned on sandbox for my app. Sandbox means the OS restricts what the app can read and write. In this case, it denies the app reading the installed Qt libraries, only allowing the app to read libraries (frameworks) from the app's bundle (package.) It would happen later, on a user's deployed machine.

              That almost explains why Qt doesn't already include the apps bundle in the library search path: the sandbox concept is relatively new and unique to the OSX platform. So it's one platform difference that Qt doesn't yet address? On other platforms, at installation time the app's packaged libraries (dependencies) are moved from the app's package to standard directories, or on Linux, downloaded and installed by the package manager.

              (For me, Qt5.3, Python3.4, PyQt5, pyqtdeploy, macdeployqt, and 'qmake -spec macx-xcode foo.pro' to move a Qt project to Xcode5.1, all reasonably work.)

              1 Reply Last reply
              0
              • B Offline
                B Offline
                bootchk
                wrote on last edited by
                #7

                yuichi: thanks for the Python snippet.

                How does your app know it is deployed? If 'deploy' is a compile-time flag, I think it makes more sense to not remove the existing path. Then addLibraryPath() prepends. Then the same code base works whether deployed or not.

                1 Reply Last reply
                0
                • B Offline
                  B Offline
                  bootchk
                  wrote on last edited by
                  #8

                  Also,

                  @filePath = os.path.dirname(os.path.abspath( file ))@

                  does NOT always return something like "APP_DIR/Contents/Resouces". At best it might return something like ..../Contents/MacOS, in other words, the path to the directory which contains the executable in the app bundle.

                  Worse, on a sandboxed app, it seems to return:

                  @/Users/bootch/Library/Containers/org.Pensool.pensool/Data/:/pensool@

                  in other words, to a copy of the app that was placed in a sandbox. I don't understand that path, and your code doesn't seem to work in this case.

                  I have yet to try a Python equivalent to Paul's solution:

                  @QDir dir(argv[0])@

                  And I have seen conflicting advice about whether QCoreApplication.applicationDirPath() will work before an application instance is created. It is a class method, so I don't see why it wouldn't.

                  1 Reply Last reply
                  0
                  • B Offline
                    B Offline
                    bootchk
                    wrote on last edited by
                    #9

                    It seems that argv[0] on a sandboxed app returns just the app name, not a path, e.g. 'myApp' instead of .../Contents/MacOS/myApp. So Paul's solution above doesn't work on a sandboxed app.

                    Also, indeed applicationDirPath() prints a warning if it is invoked before a QApplication is instantiated.

                    Re the path returned by os.path.dirname(os.path.abspath( file )) , which has a colon in it. That is strange to me. Only Windows paths typically have colons in them. Maybe it is part of Apple's sandboxing technology, and is a form of network path? If so, I'm not sure whether either Python's os.path module or Qt's QDir class deal with it correctly yet.

                    1 Reply Last reply
                    0
                    • Z Offline
                      Z Offline
                      zethon
                      wrote on last edited by
                      #10

                      [quote author="bootchk" date="1401976977"]It seems that argv[0] on a sandboxed app returns just the app name, not a path, e.g. 'myApp' instead of .../Contents/MacOS/myApp. So Paul's solution above doesn't work on a sandboxed app.[/quote]

                      What version of Qt? I am using 5.3 and I am getting the entire path from argv[0]. However, one interesting thing is that the line:

                      QDir dir(argv[0]);

                      Will initialize 'dir' with the appname as another folder. Hence, if argv is: /Applications/MyApp/Contents/MacOS/MyApp, QDir will treat that as a folder and you essentially have to cdUp 3 times.

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved