Deployment problems on Mac OSX
-
Thanks again Volker.
I ran the otool command and this is the result for myConsole and libmylibrary:otool -L myConsole.app/Contents/MacOS/myConsole:
@
myConsole.app/Contents/MacOS/myConsole:
@executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui (compatibility version 4.7.0, current version 4.7.4)
@executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore (compatibility version 4.7.0, current version 4.7.4)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1094.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
@otool -L myConsole.app/Contents/MacOS/libmylib.1.0.0.dylib:
@
myConsole.app/Contents/MacOS/libmylib.1.0.0.dylib:
libmylib.1.dylib (compatibility version 1.0.0, current version 1.0.0)
@executable_path/../Frameworks/QtOpenGL.framework/Versions/4/QtOpenGL (compatibility version 4.7.0, current version 4.7.4)
@executable_path/../Frameworks/QtGui.framework/Versions/4/QtGui (compatibility version 4.7.0, current version 4.7.4)
@executable_path/../Frameworks/QtNetwork.framework/Versions/4/QtNetwork (compatibility version 4.7.0, current version 4.7.4)
@executable_path/../Frameworks/QtCore.framework/Versions/4/QtCore (compatibility version 4.7.0, current version 4.7.4)
/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
/System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 52.0.0)
/usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1094.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 159.1.0)
@I am not sure if the "/usr/lib" paths or the "/System/Library" paths might be problematic?
I actually ran "macdeployqt myConsole.app" after I copied the libmylibrary.dylib into the MacOS folder.
-
macdeployqt is your friend. The second tool listing looks good. Is the app still not starting?
- Is your mylibrary lib a plugin? If not, there is no need to load it with QLibrary, just link it.
- If you use open, the command line output is swallowed. Just run the executable instead, without open: ./myConsole.app/Contents/MacOS/myConsole It should then also print errors in case the dynamic linker misses something.
[EDIT: fixed list formating (* instead of -), Volker]
-
Thank you Miroslav,
I am using macdeployqt. The "libmylibrary.dylib" is not a Qt plugin. It is just a shared library that also uses Qt. Actually the libmylibrary will build the QApplication. It runs fine from QtCreator.
There are 2 things I am wondering about:
when I load the "libmylibrary.dylib", I specify
@
QLibrary* lib=new QLibrary("libmylibrary");
@and not
@
QLibrary* lib=new QLibrary("libmylibrary.1.0.0.dylib");
@The other point I was wondering about: when I copy the "libmylibrary.1.0.0.dylib" into my bundle, I do a simple copy and paste. Should I use the "cp -R" command instead?
Edit: Actually, compiling "myLibrary" produces following 4 files:
@
libmylibrary.1.0.0.dylib
libmylibrary.1.0.dylib
libmylibrary.1.dylib
libmylibrary.dylib
@I always copied and pasted all 4 files into the bundle's MacOS directory before running macdeployqt
-
Just answering from the top of my head:
- If mylibrary is just a plain library, you need to link it at link time, not load it at runtime. Check out the -L <path> and -l <libname> statements in qmake.
- Once the library is properly linked, macdeployqt should take care of copying it over automatically. No manual copying should be required.
- The use of QLibrary should be unnecessary. You are trying to do the linker's job.
-
Thanks again for your help Miroslav.
myLibrary is a shared library. It is loaded by "myConsole", but also by non-qt plugins. Each of thoses plugin will be able to call myLibrary's API functions. Following are the 3 types of elements that I have:
@
*myConsole (client application)
- Is in charge of dynamically loading and binding "myLibrary"
- Is in charge of dynamically loading and binging various plugins (non-qt plugins)
- Except for the QLibrary function to load and bind "myLibrary", this application doesn't directly require Qt*myLibrary (collection of API functions)
- Contains a collection of API functions. Those functions need to be accessed by "myConsole" and the plugins (see below)
- Heavily relies on Qt*various plugins
- They do not rely on Qt
- They need to access the API functions of "myLibrary"
@For the tests however, I do not load any of above mentionned plugins.
what makes me crazy is that everything works like a charm when launched from QtCreator. I only have trouble with the bundling.
I could actually also write the "myConsole" without Qt, by using XCode. Would that simplify my problem? I used Qt for "myConsole" simply because I don't yet have any experience with XCode, but already know Qt from other platforms
-
Ok, understood. The QLibrary use is needed in that case (sorry if I led you in the wrong direction).
What could happen is that the paths deviate from what QLibrary expects. You could assemble an absolute path using QCoreApplication::applicationFilePath to see if that is the problem (try QCoreApplication::applicationFilePath + ../MacOs/libmylibrary.1.0.0.dylib, check that it is really there). From the docs, it seems like QLibrary will first try using the passed in name as an absolute path.
-
What you could also try is adding the frameworks directory of your bundle to the library path of QCoreApplication (QCoreApplication::addLibraryPath). I think the bundle frameworks directory is not added automatically.
The docs are a bit vague about the search order of QLibrary, though.
-
Thanks again Miroslav!
I got it to work, but there is something strange going on:
Following does not work:
@
QCoreApplication::addLibraryPath("/Users/me/Documents/myConsole/myConsoleRelease/myConsole.app/Contents/MacOS");
QLibrary* lib=new QLibrary("libmylibrary");
@But following works:
@
QLibrary* lib=new QLibrary("/Users/me/Documents/myConsole/myConsoleRelease/myConsole.app/Contents/MacOS/libmylibrary");
@Might this be a bug in the addLibraryPath function?
Does anyone know from the top of his head a non-Qt command to get the path location of the current application? (including the inside folders of the bundle, so that I can build the absolute path of my library without having to build a QApplication object in order to use "applicationDirPath") -
Regarding the first question, the docs do not specify if QLibrary looks into the app library path.
Qt's applicationDirPath() is the most portable way to get to the executable path as far as I know.
-
Thanks Miroslav,
I don't wanna use applicationDirPath() because this requires me to build a QApplication object (and this is done in the "MyLibrary"). Finally, I solved my problems with following code:
@
std::string libLocation(argv[0]);
libLocation.erase(libLocation.end()-9,libLocation.end()); // not elegant, but I just remove the "myConsole" string
chdir(libLocation.c_str());
QLibrary lib=new QLibrary("libmylibrary");
@Thanks to both of you for your help... as it seems now it was a small thing, but it took a lot of effort for me and I wouldn't have found it without your help!!
Cheers
-
the library path of QCoreApplication is not used. The docs state:
bq. When loading the library, QLibrary searches in all system-specific library locations (e.g. LD_LIBRARY_PATH on Unix), unless the file name has an absolute path.
QCoreApplication::libraryPath() is not mentioned here. You might want to try to set the DYLD_LIBRARY_PATH environment variable before you try to load the library. You can try the following snippet, I did not test it, though.
@
QByteArray dyldPath = qgetenv("DYLD_LIBRARY_PATH");
if(!dyldPath.isEmpty())
dyldPath.append(":");
dyldPath.append(QCoreApplication::applicationDirPath());
qputenv("DYLD_LIBRARY_PATH", dyldPath);// call QLibrary load after the stuff above
@Please be aware that on Linux the environment variable is LD_LIBRARY_PATH and on Windows you will have to use PATH (although by default Windows looks into the directory that contains the .exe).
-
Thank you very much Volker!