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?
↧