Embedded Framework conflict with version located outside the bundle - cocoa

One of my Mac applications contains a framework which I embed into the application bundle. Now I have found some evidence that on some customer machines the application links against the same framework located in the /System/Library/Frameworks folder.
I'm obviously missing something when it comes to linking the embedded framework to the application in XCode, so here's how I've done it.. and perhaps you can point me to the missing step:
1) I drag the framework project into my project and set up the dependency between both projects
2) I drag the build product of the framework project to the "Link Binary with Libraries" build phase of my target
3) I drag the build product of the framework project to the "Copy Framework Files" build phase of my target set to "Destination: Frameworks"
This all works great but somewhere I need to specify that I want to link with the embedded version of the framework rather than any framework version that might be found on the system. Is there a search path to be set somewhere? or "static" link?
Any help would be appreciated.
Best regards,
Frank

Sounds like you might be missing a key step. You also need to set the "install name" of your embedded framework.
When you link a framework or dynamic library, your app will look for the framework at the path specified by framework's install name. This should specify a relative path for embedded frameworks. If it is an absolute name it will pick up the system installed version, even if you've embedded the library.
To examine the install name do the following and look at the first location.
otool -L <framework-binary>
These two blog posts explain the issue and also how to set everything up properly:
http://www.mikeash.com/pyblog/friday-qa-2009-11-06-linking-and-install-names.html
http://www.dribin.org/dave/blog/archives/2009/11/15/rpath/
Additionally, if you're compiling a dylib from the command line (say an open source library) just add the following to your CFLAGS to set your install name.
-install_name '#rpath'
If you want to modify an existing binary's install name use 'install_name_tool'.
Also be sure your copy files build phase is copying the right files into the right places in your app bundle.

Related

Xcode: How do I include a framework in my application

I am new to Xcode programming and have finished my first game wich uses SDL. When starting it on another mac it didn't work until I added the SDL2.framework into the /Library/Framework directory. Now I've been searching forever on how I could include the framework in the app because I didn't want to install the SDL2.framework on every mac I wanted to play the game on but I didn't find anything that worked… I've found something like "turn off ZeroLink" but didn't find it in Xcode… What setting do I have to change so Xcode will include the framework in the finished .app?
The following tutorial details setting up an SDL project in Xcode and the final, optional section, covers packaging the framework with the app
http://zamma.co.uk/setup-sdl2-in-xcode-osx/
Essentially what you need to do is:
Create a Copy Files entry in the build phases
Set the Destination field to be Frameworks
Add the SDL2.framework in the list to be copied
Set the parameter Runpath Search Paths (under Linking in the Build Settings) to be #executable_path/../Frameworks

Dependency Analysis Warning - Skip Install is disabled

When I archived my application I got this error for all my custom frameworks
Warning: Installation Directory starts with '#executable_path' but
Skip Install is disabled.
I added my frameworks to my application my linking to them first and then creating a copy build false to the frameworks directory.
On each framework project I configured the Installation Directory to "#executable_path/../Frameworks" based on several tutorials I searched for on google. I believe this is to avoid installing the frameworks on the user's library (not sure).
Just to be clear, I want my frameworks to ship inside the application bundle, under the frameworks folder.
Now, I see a property named Skip Install on each of the frameworks projects build settings. Here is a description of what it means:
SKIP_INSTALL Description Activating this setting when deployment
locations are used causes the product to be built into an alternative
location instead of the install location. [SKIP_INSTALL]
When I activate this property the warning is gone, but can someone explain to me what this is? Because it implies that the #executable_path/../frameworks/ will be ignored.
In XCode 6.3.1:
Go to Build Settings, turn on 'All' not just 'Basic'
In the 'Deployment' section, set 'Skip Install' to Yes.
This will fix the warning. The thinking behind it is, if you're including the framework in your executable(s), then you don't want to install it separately
I am not sure but you have to set "Framework Search Paths" in Build Settings and remove Preprocessor Macros Debug value..
May you get help..

Including OSXFUSE framework in XCode project

I have build a App based on OS X FUSE (ie I have my own file system based on OS X FUSE).
When OSXFUSE is installed I can of course include the OSXFUSE.framework from /Library/Frameworks.
However when I distribute the App I cannot expect the user to already have it installed, so I tried to include the framework with the bundle as follows:
dragged the framework from /Library/Frameworks to my project
created a new Copy Files build phase (with target Frameworks)
added the framework to that copy build phase
However when I run that on a system without FUSE installed I get an error:
dyld: Library not loaded: /Library/Frameworks/OSXFUSE.framework/Versions/A/OSXFUSE
Referenced from: /Users/me/Library/Developer/Xcode/DerivedData/
Shouldn't the copy build phase prevent this? What am I missing here?
I finally found out that I can tell XCode explicitly to weakly link a framework by changing the required flag to optional.
This can be done in Project Overview > Target > Linked Frameworks and Libraries. Next to each framework is a dropdown-menu where you can select optional.
So my question is actually a duplicate of this How do I weak link frameworks on Xcode 4?
I believe that the OSXFuse framework needs a corresponding kernel module to work. This has to be installed separately so you would have to put together an installer package that first installs the kernel module and the preferences pane, and then installs your application.
Alternatively, you could notify the user that the module needs to be installed separately and provide a download link or something to that effect.

Error "Library not loaded" when launching app

I have created a Mac app which uses the RMSharedPreferences framework. When opening the app, it immediately crashes and I get the following error:
Dyld Error Message:
Library not loaded: #rpath/RMSharedPreferences.framework/Versions/A/RMSharedPreferences
Referenced from: /Users/USER/Desktop/MyApp.app/Contents/MacOS/MyApp
Reason: image not found
It seems that it can't find the framework. I have tried adding a copy files phase to the target which should copy the framework and when browsing the contents of the app in Finder, it seems that it is copied correctly.
Does anyone know what might cause this error?
EDIT: Setting the framework to optional does make the application launch without any errors but the application does not fully work. Any RMSharedPreferences related calls will be ignored.
Since you are bundling the framework with your app, you should set the framework's install location. You can set that in your framework target build setting "installation location". Use something like:
#executable_path
You could also use a separate folder for your frameworks, then you would use:
#executable_path/../Frameworks/
In case you can't rebuild the framework (which is not yours, but I am saying in general), you can modify a prebuilt framework installation path like this:
install_name_tool -id #executable_path/../Frameworks/<framework_name> <your_framework>
Here you can find a reference for this.
If you are going to bundle a framework inside another framework, you can use #loader_path instead of #executable_path.
#rpath is a more flexible keyword, and its use is recommended.
The better way to do this is to set the "Runpath Search Paths" build setting in Xcode.
This avoids the need for an additional build phase script to modify the framework.
For instance, in your situation, you could set "Runpath Search Paths" to
#executable_path/../Frameworks
or
#loader_path/../Frameworks
if you're trying to load the framework from within a framework.

Using frameworks in a command line tool

I've built a command-line utility (Foundation tool) in Xcode, using Cocoa. The tool makes use of a 3rd party framework.
Everything works OK in Xcode, but how do I deploy this program?
If I run the app from Finder, it can't find the library because it's looking in ../Frameworks/etc. Can I statically link in the 3rd party framework?
Unfortunately, there is no way to bundle a framework with a command-line Utility in OS X and I suspect that the framework you're linking to is expecting to be bundled in the app bundle's Frameworks/ directory. If you have access to the framework source code, you can compile a static library and statically link it to your application (or include the source in your application target directly). If you don't have the source code or you don't want to statically link the library for some reason, there are two remaining options:
If you have access to the system-wide /Library/Frameworks folder, you can install the 3rd party framework there. This require that the framework's Installation Path (the INSTALL_PATH build setting) be set to /Library/Frameworks at build time or that you use the install_name_tool to change the frameworks install path to /Library/Frameworks (if you don't have the framework's source code).
Build an application bundle (as if you were building a GUI app) with your command-line utility as the app bundle's executable (i.e. in AppBundle.app/Contents/MacOS/). You can then copy the 3rd party framework to the app bundle's frameworks directory. You can then put the app bundle anywhere you want and create a symbolic link to the command line utility.
Option 1 is definitely the more accepted approach, but I've used option 2 when there was a valid reason.
You can find more information on building, linking, and installing frameworks in Apple's Frameworks Programming Guide.
Another way, if you have the source code for the framework, is to add a static library target and build a static lib from it. Then you can statically link it into your command-line tool.
As of Xcode 9.3.1, I was able to have the framework added to the command line tool by setting the Mach-O Type to Static Library for the framework. Then in the command line target make sure to add the framework to the Target Dependencies & the Link Binary With Libraries Build Phases. The built executable was then able to run with no issues.
You can use marathon to manage dependencies
https://github.com/JohnSundell/Marathon
This would need more thought if you wanted to distribute app. (You would probably want to install into frameworks folder in that use case.) your mileage may vary with this solution.

Resources