Setting dylib paths as a XCode build step - cocoa

I have a Cocoa application as XCode project that has several supplementary bits of functionality as dylib targets.
When XCode builds the project, it places all the build outputs in a single folder: The .app bundle and the dylib files. And when executed from the XCode debugger, the .app launches.
I can't however launch the application from finder.
How do I setup XCode to 'deploy' the app in a standalone state? I have found that I can use ld on the actual app binary to contain a relative path to the dylibs: #executable_path/../../mylib.dylib
Running a script after each build seems wrong: there must be some way (that Im totally missing) to do this easily from inside XCode - it must be a common issue surely?
It looks like that XCode supports having #executable_path, #loader_path and #rpath used in the Target Info > Build > Linking > Dynamic Library Install Name setting (LD_DYLIB_INSTALL_NAME) setting.
The help text says: "Sets an internal "install path" (LC_ID_DYLIB) in a dynamic library. Any clients linked against the library will record that path as the way dyld should locate this library"
This seems very promising, but usability is a problem if I need to link dylibs in multiple paths against a common library - the relative path is going to be different each time.
Running my testapp from finder, I get the following (relevant) error text
Dyld Error Message:
Library not loaded: #executable_path/../../util.dylib
Referenced from: /Volumes/data/Code/TestApp/build/Debug/TestApp.app/Contents/MacOS/TestApp
Reason: image not found
util.dylib is in /Volumes/data/Code/TestApp/build/Debug/ so I am confused :/

You should use a Copy Files build phase to copy the dylib to the app's bundle when building the app. You'll want to copy it to Frameworks. You can then set the install path to #executable_path/../Frameworks/mylib.dylib.

Related

Loading the library from Bundle vs compiled location

I'm trying to build and run my program in C++ from inside Xcode.
I'm using wxWidgets which I build myself inside ~/wxwidgets/buildOSX.
An Xcode project linker option set to use that location in order to build my program.
I also made a little script in the Xcode project->Build Phases, which copies all the dylibs into the Bundle and uses install_name_tool -change to redirect ldd to load the libraries from the new location.
However, what I see in the Debug Console when I press Command + R is that all the libraries including wx one are loaded twice - first from the Bundle and then from the location I build them from. And so I end up with 2 copy of every single library
How do I mitigate that?
P.S.: I believe that this is the reason for Crash in Xcode but success from Terminal. And so fixing it will resolve the crash here.

OSX App crashing on load when ParseOSX framework with Dyld Error

I have an OSX app and I have added the ParseOSX sdk. I have followed all the instructions on the quick start page (https://www.parse.com/apps/quickstart#parse_data/desktop/osx/existing)
The app is running fine in Xcode (Version 5.1.1 (5B1008)) but when I archive and create a package and install this. I get the following Dyld error;
Dyld Error Message:
Library not loaded: #executable_path/../Frameworks/ParseOSX.framework/ParseOSX
Referenced from: /Applications/MyApp.app/Contents/MacOS/MyApp
Reason: image not found
It goes on and lists the Binary Images loaded.
Searching the web I found reference to adding a copy files build phase and adding the parse framework to that with the destination set to Products directory.
So it appears there is a dynamic lib not being installed somewhere.
UPDATE:
I just cleaned the build folder and now the app will not even run under Xcode. I get:
dyld: Library not loaded: #executable_path/../Frameworks/ParseOSX.framework/ParseOSX
Referenced from: /Users/Ants/Library/Developer/Xcode/DerivedData/MyApp-hjrbgyhzpwnxhiaskxpojqyqxnvh/Build/Products/Debug/Actual.app/Contents/MacOS/MyApp
Reason: image not found
UPDATE 2:
It turns out when you are in the quick start page. If you chose the new app option you get a Xcode project. This compiles. Going through it I can see that there is is a Copy Files step that copies the ParseOSX.framework into the Frameworks destination. Tried this is my app and I now get a signing error
/Users/Ants/Library/Developer/Xcode/DerivedData/MyApp-hjrbgyhzpwnxhiaskxpojqyqxnvh/Build/Products/Debug/MyApp.app: code object is not signed at all
In subcomponent: /Users/Ants/Library/Developer/Xcode/DerivedData/MyApp-hjrbgyhzpwnxhiaskxpojqyqxnvh/Build/Products/Debug/MyApp.app/Contents/Frameworks/ParseOSX.framework
I ran into the same problem with xcode 6.1. Fixed it by adding ParseOSX.framework to "Embedded Binaries" on the general tab of the Targets page.
Two things fixed this for me.
First I needed to add a copy files section to the build phases and copy the ParseOSX.framework into the Frameworks destination.
And second, I needed to add --deep to the "Other Code Signing Flags" in the Code Signing section of Build Settings. It now signs the frameworks being copied it seems.
I was updating an existing parse project to the newest SDK (1.12.0) using Xcode 7.2 and ran into the same problem.
The solution for me was to set Runpath Search Paths to #executable_path/../Frameworks.
I found this by comparing the Starter project from Parse to my project.

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

Install Fragaria framework

I was looking for a way to implement syntax highlighting on my cocoa app and I found the great Fragaria framework https://github.com/mugginsoft/Fragaria. Unfortunately I seem to be unable to install the framework in my app.
Here are the steps I follow:
Compile the framework from the source code target
Add the framework to the "Link Binary with Libraries" build phase of XCode 4
Drag the framework into "Copy Bundle Resources"of build phase
Unfortunately when I try to build my app I get this error:
dyld: Library not loaded:
#executable_path/../Frameworks/MGSFragaria.framework/Versions/A/MGSFragaria
Referenced from:
/Users/dedalus/Developer/DEGS/trunk/build/Debug/DEGS.app/Contents/MacOS/DEGS
Reason: image not found
Which step am I missing?
Don't add the framework product to the Copy Bundle Resources build phase. Instead, create a new Copy Files build phase, set its destination to the Frameworks directory and add the framework build product to this phase. The Copy Bundle Resources build phase copies the framework to the resources subdirectory (Contents/Resources on OS X), but the dynamic linker expects it to be in the frameworks subdirectory (Contents/Frameworks on OS X). The newly added Copy Files build phase will put it there.
BTW, the error you're seeing is a run-time error, not a compile-time error. So strictly speaking you get this error when running the app, not when building it.

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