Trace dylib loading on Mac OSX - macos

I'm trying to build a Qt-based application on Mac OSX, and something in my application bundle is pulling in a Qt library from /Library rather than from the application bundle.
I've done this successfully in the past, so I know about using install_name_tool to link applications and libraries to the bundle versions of libraries. I've done this, but I must be missing something. I've tried setting DYLD_PRINT_LIBRARIES, but I'm not really sure how this helps: I can see which Qt library is being pulled in from /Library first (QtXml), but I don't know which file in the bundle is pulling in this library.
Is there some trick to tracing back which file is loading a particular library?

Use otool utility to see what libraries are used by your app and where the app expects to find them:
otool -L yourApp.app/Contents/MacOS/yourApp

Related

OSX: start app with runtime-dependent dylibs

OSX 10.10 Yosemite.
My application depends on Intel IPP.
At compile time it depends on 2 dylibs, but these depend from other dylibs, which are loaded at runtime (and not displayed in otool -L) . When starting my application does not find these libraries.
I do not understand how can I specify for my app (or for the compile time dependent dylibs) a folder to search a path for runtime dylibs.
As far as I can understand, it is necessary to use rpath. But what exactly should be done? How to set runtime search path? Do I need to set a 'rpath' for the executable file or for the dylibs?
I think you will have to use install_name_tool command to add the dylib.
Don't think you can setup a folder that can magically load all the dylib in it. It's against the purpose of code signing and security.

Qt + CMake for OSX Bundle: Cocoa Platform Plugin

I'm trying to make a bundle for a Qt based application using CMake.
Things seem to be working fine in terms of linkages, but trying to run the app gives me the error:
This application failed to start because it could not find or load the Qt platform plugin "cocoa".
Available platform plugins are: cocoa.
I'm not sure what this means as the two lines of output seem conflicting. The directory platforms/ (which contains libqcocoa.dylib) is in MyApp/Contents/Resources/bin/. Note that the MyApp executable is there as well.
While the platform library was in the correct position relative to the executable, the libqcocoa library was expecting other Qt libraries to which it was linked to be in specific directories. I used a script with install_name_tool -change commands to modify these paths.

OSX Xcode - Packaging dependencies libmysqlclient.18.dylib

This may well have been asked before I just couldn't figure out the right term to search.
I'm writing a client-server application to run on an OSX desktop which will talk to a MySQL server on the local network. It seems long-winded to implement a web-services API when basically a bunch of SQL statements will be perfect internally.
I've wrestled with the install procedure for MySQL server on my development machine, ad had to resort to symlinking libmysqlclient.18.dylib into /usr/lib even though i'd put the include path in header search paths.
What I need to know is how do I create a .app file I can send to other machines that will have access to the libmysqlclient.18.dylib file?
I'm used to Windows having installers to do this and a bit new to OSX programming although i've been doing Obj-c for iDevices for 2 years.
Is there a setting which allows the library to be copied into the .app file or do I need to install the mysql connector on each machine - if so, how do I get around the symlink issue, ideally I need it to work from the stock folders.
If this has been answered somewhere else, please point me in the right direction.
At build time the static linker on OS X, ld, writes the shared library identifier of each library that your application links against in to the application binary. At run time the dynamic linker, dyld, attempts to load each shared library from the paths specified in the application binary. You can see this information using otool -L YourApp.app/Contents/MacOS/YourApp.
The fact you needed to symlink libmysqlclient.18.dylib in to /usr/lib suggests that the shared library identifier of libmysqlclient.18.dylib is something like /usr/lib/libmysqlclient.18.dylib. To include the library in your .app bundle in a way that your application will use it rather than looking in /usr/lib you need to:
Change the shared library identifier of libmysqlclient.18.dylib so that dyld will look for the binary relative to your application binary. This is typically done by running install_name_tool -id #executable_path/../Frameworks/libmysqlclient.18.dylib libmysqlclient.18.dylib.
Copy the modified libmysqlclient.18.dylib in to the Frameworks subdirectroy in your application bundle. This is typically done using a Copy Files build phase in your Xcode project.
You should then be able to verify that the install name written in to your application binary is #executable_path/../Frameworks/libmysqlclient.18.dylib rather than /usr/lib/libmysqlclient.18.dylib (using otool -L YourApp.app/Contents/MacOS/YourApp again). If the install name isn't correct then you'll need to ensure that your linker search path is set up to find your modified version of libmysqlclient.18.dylib ahead of any other versions you may have.

Missing file when deploying Qt app on Mac OSX

I'm trying to deploy a Qt application on Mac OSX so I'm running this command:
macdeployqt Example.app
It mostly seems to work as the executable grows in size so I assume the relevant plugins and libraries are being added. However, in the end macdeployqt outputs this error message:
ERROR: no file at "/usr/local/pgsql/lib/libpq.5.dylib"
Does anybody know what this file is? Do I need to install something to make it work?
The documentation states: SQL driver plugins are deployed if the application uses the QtSql module. The macdeployqt tool does not know which plugins your application uses, and tries to deploy all of them. Your application does not link directly with any of the plugins, so there's no way to tell what it uses merely by looking at the executable. The macdeployqt tool would need to parse the code of your application, or use potentially breakable heuristics to scan for sql driver name strings. It's a shortcoming of the macdeployqt tool.
A temporary workaround would be to move the unused plugins out of the plugins/sqldrivers folder in QtSdk.
Note: The Example.app is not an executable. It is an application bundle -- a folder with stuff in it and you can inspect its contents in the usual way: from the shell, or via Finder by right-clicking on the application bundle.

Deploying Qt Frameworks with Mac app and usage of otool

I have a problem deploying Qt frameworks with my Mac app, and I hope some will have a clue why I get this error, when I run the app on clean Mac, i.e. not a developer Mac.
OS: 10.7 .2 and using XCode
Error msg:
Library not loaded: #loader_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
Referenced from:/Users/someUser/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle/Contents/MacOS/../Frameworks/../Frameworks/QtXml.framework/Versions/4/QtXml
Clearly something is wrong since the QtXml is referenced from /../Frameworks/../Frameworks, which doesn’t exists.
This is the set up: I have a dylib that uses QtCore and QtXml (not by my choosing, but for now I need those two frameworks), the dylib is used in a NSBundle, which is loaded by the main app, the bundle is located in the resource folder. The dylib is moved by Copy Files Build Phase to the folder Contents/Frameworks and with otool the install_name is set to (as stated by http://doc.qt.digia.com/4.3/deployment-mac.html):
#loader_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
#loader_path/../Frameworks/QtXml.framework/Versions/4/QtXml
then the Qt frameworks are moved to Contents/Frameworks and the install_name of the is set to:
#executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
and for the QtXml
#executable_path/../Frameworks/QtXml.framework/Versions/4/QtXml
with reference to QtCore:
#executable_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
Now when I run the app on the developer mac it clearly works since Qt is installed, but when moved to a clean mac I get the error msg, readable in the Console app.
I’ve tried to change the executable_path to loader_path, but this didn’t work.
I have no idea what I’m doing wrong or why it won't for, and have not been able to find anything on Google, of course I could be looking at the wrong places. Any ideas how to fix this problem?
This is the entire error message:
MainApp: Error Domain=NSCocoaErrorDomain Code=3587 "The bundle
“Library” couldn’t be loaded because it is damaged or missing
necessary resources."
(dlopen_preflight(/Users/someUser/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle/
Contents/MacOS/Library): Library not loaded:
#loader_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
Referenced from: /Users/ someUser /Downloads/
MainApp.app/Contents/Resources/Lib/Library.bundle/Contents/MacOS/../Frameworks/../Frameworks/QtXml.framework/Versions/4/QtXml
Reason: image not found) UserInfo=0x107c5d5d0
{NSLocalizedFailureReason=The bundle is damaged or missing necessary
resources., NSLocalizedRecoverySuggestion=Try reinstalling the
bundle.,
NSFilePath=/Users/someUser/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle/Contents/MacOS/Library,
NSDebugDescription=dlopen_preflight(/Users/someUser
/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle/Contents/MacOS/Library):
Library not loaded:
#loader_path/../Frameworks/QtCore.framework/Versions/4.0/QtCore
Referenced from:
/Users/someUser/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle/Contents/MacOS/../Frameworks/../Frameworks/QtXml.framework/Versions/4/QtXml
Reason: image not found,
NSBundlePath=/Users/someUser/Downloads/MainApp.app/Contents/Resources/Lib/Library.bundle,
NSLocalizedDescription=The bundle “Library” couldn’t be loaded because
it is damaged or missing necessary resources.}
On the development mac everything works because the Qt libraries are installed. On any mac you ship the app to, though, this likely won't be the case. The Qt suite comes with a tool called macdeployqt to fix this. So in a terminal, after you've compiled your application, do something like:
# cd my-cool-app-Desktop
# macdeployqt my-cool-app.app
Note that it can also be used to create a .dmg file for shipping everything together:
# cd my-cool-app-Desktop
# macdeployqt my-cool-app.app -dmg
Once you've done that, the .app directory or .dmg file can be given to someone else without Qt installed to use and run as they normally would.
The one caveat is that the next time you try to run it on your developer machine, it may complain about multiple shared libraries installed. So once you've copied it else where in order to distribute it, remove the entire .app directory and let qtcreator (or whatever) rebuild it.
UPDATE
As stated compiling QT to static libs is the way to go. With the release of Mavericks (10.9) we need to codesign frameworks as well (http://furbo.org/2013/10/17/code-signing-and-mavericks/), and with QT4.8.5 there are some issues (https://bugreports.qt-project.org/browse/QTBUG-32896). Even with suggested fixes I still had some issues when running the app on a clean machine. Therefore, I ended up with compiling Qt5.2 to staticlibs, link them in the app, and codesign them.
OLD
Problem sovled, I moved the Qt-frameworks into the app bundle in Contents/Frameworks and with otool set the path to #executable_path/../Frameworks, i.e. moved it out of my library bundle. Yes the solution is simple, but I'm still not sure why the library executable couldn't find the frameworks when using #loader_path.
The best solution would probably be to use a static library and not wrap it in a bundle...you learn everyday ;)

Resources