Where does mac osx app require dependent libraries? - macos

I have built a Qt project under mac, but I have problems executing.
Its dependencies have several dylib .
When building the project, the make tool only asks for one of the libs (for example lib.1.0.0,dylib out of lib.1.dylib, lib.1.0.dylib, lib.1.0.0.dylib, lib.1.0.0.0.dylib) - so I know to put it in the .pro file
Some look like links - but it is not always the lib version that looks like a file that is required as a dependency.
But at run time, I don't know which dylib I need, and where to put it.
I tried to place all 4 lib versions in the folder where the app was created - the project folder - but the app didn't execute.
Having done the same in Linux, I had to put the libs in a place set on path - like /usr/local/libs
Where does mac like its libs (shared libs ?) in order to run ?

You should read this document on deploying Qt applications. It will answer your questions. Moving your libraries to a system library path is usually not a good idea.
http://qt-project.org/doc/qt-5/macosx-deployment.html
To sum this up though you need to change the binaries to tell them where the libs are using the otool command.

Related

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.

Trace dylib loading on Mac OSX

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

Qt installation directory woes

I want to use Qt in my new project. An installer for my target compiler (VS2010 64bit), does not exist.
I am using Windows 7 64-bit with Qt 5.1.1.
A colleague of mine is also planning on using Qt and has managed to compile it for my target compiler (which he uses as well). He has built it in some directory, say DirA. He graciously gives me a copy of his entire Qt SDK build (binaries, examples, headers, and all), and I copy it to DirB on my machine.
I need it in DirB, because that is where all my 3rd party libraries are installed, and my CMake scripts know how to find them. I also added the Qt bin folder to my path.
Problems ensue. Qt binaries for some reason have the install path (in this case the build path) hard coded within them. So even though the Qt bin folder is in my path (so DLLs are found), Qt's DLL(s) are looking in the wrong place for the windows "plugin". They are looking in DirA, which does not exist on my machine.
So from what I found researching, using a qt.conf file specifying the install path root, is supposed to be the way to go. I add one to my Qt bin dir, and now Qt binaries (assistant, qmake, etc) can run.
But now I build one of the examples. Builds fine. Run the exe, Qt DLLs load, and then it crashes because it can't find plugin directory.
A work-around my colleague and I found that seems to work, is to copy my qt.conf file to the directory my exe resides in. After doing that the exe runs.
But this does not seem right. My exe can find the Qt DLLs, but the Qt DLLs it loads can't find qt.conf. They don't know to look in their own containing folder. I must have qt.conf in my working directory (my exe dir) for it to be found and used.
Does anyone know why this might be happening, and know of a way for me not to be forced to have a qt.conf file in my exe's dir? I can't accept this requires a rebuild of Qt. There must be some other way.
You can put qt.conf into your binary. Using the resource system.
From the Qt docs:
Without qt.conf, the Qt libraries will use the hard-coded paths to
look for plugins, translations, and so on. These paths may not exist
on the target system, or they may not be accesssible. Because of this,
you need qt.conf to make the Qt libraries look elsewhere.
QLibraryInfo will load qt.conf from one of the following locations:
:/qt/etc/qt.conf using the resource system
Or:
Using QApplication::addLibraryPath() or
QApplication::setLibraryPaths(). This approach is recommended if you
only have one executable that will use the plugin.
If you add a custom path using QApplication::addLibraryPath it could look like this:
qApp->addLibraryPath("C:/customPath/plugins");

Deploying cocoa application and its C++ dylib how to pack them?

I am new to cocoa and mac development. I have written an application which is combination of objective-c using cocoa framework and backend written in C++ library dylib.
I am using xcode 4.6 and have the above two projects Cocoa app and my C++ library. C++ is also my own project.
Now it is time for deployment. I want to make a pkg installer for it.
I could run/debug it in the xcode 4.6 because I had added search library path in the object-c project settings to be the output directory of the C++ project. Therefore it could find the dependency and run without crash.
Now in the Objective-C project tree inside the xcode I see products -> mysoftware.app file. if I find the location of this mysoftware.app file in the finder and run it, it crashes. I open the package contents of this app files and I see contentsfollowing structure
contents\(info.plist, MacOS, pkginfo, resources )
I do not see my C++ library in there, when I run mysoftware.app directly double clicking it crashes as it can not find the dylib I see the stack trace in the report window it can not find dylib, complaning that library not found usr/local/lib/mylib.dylib
I have also manually put the dylib file in the .app within the MacOS where my executable is, hoping that it will find the lib from the same directory, it did not , gave the same message above and looking from the the sane location /usr/local/lib/mylib.dylib
So my question is how do I resolve dependency of .app package for deployment, should I need to put the dylib inside the .app package ? how do I do that and then my next step would be to put this single .app thing in the pkg installer,
Thanks
This is what worked for me:
Drag the dylib into your Frameworks.
Add a Copy Files build phase, destination Frameworks and put the dylib there.
Add a Run Script phase which has the following script:
MYLIBNAME=libmylib.dylib
install_name_tool -change /usr/local/lib/$MYLIBNAME #executable_path/../Frameworks/$MYLIBNAME "$BUILT_PRODUCTS_DIR/$EXECUTABLE_PATH"
That's it. The script tells your app to load the dylib from the right place - otherwise it will complain about not finding the dylib at runtime.
Note that you don't need to change anything in the dylib itself - it could be supplied from elsewhere.
I resolved it so I am putting up this answer to help others who want to do the same.
The dylib has to go in one of the sub folders within the application bundle (i.e. mysoftware.app). Could be MacOS, Frameworks or any sub folder we decide to put it in.
The first step is in the target settings of our dylib, we set the install path to be relative to the app bundle (mysoftware.app), so in Xcode target settings of lib I set it to:
#executable_path/../frameworks
You can also use #rpath (You might want to research on that, I think it is more flexible than #executable_path)
Xcode will change the install name as well for our dylib.
Then in the Objective-C project using our dylib in the Project settings -> Build phases -> Link -> we drag our dylib here from the products node of the dylib project.
In the Objective-C/Cocoa project, the last step is to add a build step named copy files, and it should show a combo box telling you the target folder of the bundle. I set it to frameworks (this will depend on that relative path you choose when setting install path of your dylib) . The second part of the 'Copy Files' build step is to provide the souce file to copy. That's our dylib file that we want to pack in the bundle's Frameworks folder. So drag the dylib file from the products (of your dylib project) to the source file of the build step.
And that's it.
Now when we build the Objective-C or Cocoa project, if our build steps and install_path , etc are correctly configured, it should build fine. After a successfull build of the Cocoa project, go to Products -> mysoftware.app -> Locate in the Finder and when you run it, it should run fine. Since the dependency dylib is in the Frameworks folder of the bundle and correctly linked. You can see the package contents of the bundle to see if the Frameworks folder contains your dylib file.
To my surprise, the path where a dylib is stored has to be part of the dylib. So when a project links to this dylib it will copy the same path in itself, so when we run the Cocoa app which was linked to that dylib, it will look for it at exactly the same path which it copied from inside the dylib and we are responsible for telling the dylib where it exists. In the form of install_path, etc.
There are tools to manually update the dylib's install path stored in the Cocoa project using that dylib. If update the path of an existing bundle using these tools it should be changed in the client of the dylib, not required in the dylib itself.
If we've the code then we can change it in Xcode as instructed above.
otool -L my.dylib for example can be used to see the dylib install path of an existing binary lib
install_name_tool -change can be used to update the install path of existing binary lib

Xcode, building and dylibs

I've looked at a few related questions and cannot seem to find a solution for myself.
Basically I'm using the libmp3lame.dylib in my Xcode project. The install process for lame produced the .dylib and placed it in usr/local/lib and to get Xcode to build and run the project I changed the Library Search Paths to include the above folder. This works fine.
Now it's come to producing a release version and I want to include the .dylib in the bundle so that the user doesn't have to put up with an install phase or anything similar. I created a copy files phase of the target and this dumps the .dylib into the Frameworks folder in the contents of the bundle. However, running otool on the binary shows that instead of using the .dylib inside the bundle, the compiler has linked it to the usr/local/lib version (even if I delete that version).
Looking at the other results in the otool output I have other frameworks being linked to inside the bundle, just not the .dylib. Looking at the properties for both these frameworks and the .dylib in Xcode I can't see any differences other than file type.
My searching suggests I need to use rpath or similar, but I've no clue where to apply this in Xcode.
My workaround for this issue was to do the following in terminal (I've used Automator to, well, automate this):
install_name_tool -id #executable_path/../Frameworks/libmp3lame.0.0.0.dylib ~/path/to/lib/in/app/libmp3lame.0.0.0.dylib
install_name_tool -change /usr/local/lib/libmp3lame.0.dylib #executable_path/../Frameworks/libmp3lame.0.0.0.dylib ~/path/to/app/Contents/MacOS/AppName
Basically swapping the path to the library from the one in the usr local lib to the one included in the bundle.
My tip is to look at the build output, how does it actually run ld?

Resources