How do I bundle a library within a Cocoa application? - cocoa

I have the library libmysqlclient.16.dylib, which I need to have on the computer where my application is running, or I will get the following error:
Dyld Error Message: Library not
loaded:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib
Referenced from: /Users/alex/snow
server 3.app/Contents/MacOS/snow
server Reason: image not found
This is very strange, because I linked the binary with this library.
If the same dylib exists on the target computer, but in a different version (for example, Snow Leopard Server), I get an error like the following:
Dyld Error Message: Library not
loaded:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib
Referenced from: /Users/alex/snow
server 3.app/Contents/MacOS/snow
server Reason: no suitable image
found. Did find:
/usr/local/mysql/lib/libmysqlclient_r.16.dylib:
mach-o, but wrong architecture
I'd like to link against this library, but not have to use the local copy of it. Is this possible?
UPDATE - when i try to using install_name_tool i don't have any changes:
bash-3.2# otool -L
libmysqlclient.16.dylib
libmysqlclient.16.dylib:
libmysqlclient.16.dylib
(compatibility version 16.0.0, current
version 16.0.0)
/usr/lib/libSystem.B.dylib
(compatibility version 1.0.0, current
version 123.0.0)
/usr/lib/libz.1.dylib (compatibility
version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib
(compatibility version 7.0.0, current
version 7.9.0) bash-3.2#
install_name_tool -change
libmysqlclient.16.dylib
#executable_path/../Frameworks/libmysqlclient.16.dylib
Usage: install_name_tool [-change old
new] ... [-rpath old new] ...
[-add_rpath new] ... [-delete_rpath
old] ... [-id name] input bash-3.2#
install_name_tool -change
libmysqlclient.16.dylib
#executable_path/../Frameworks/libmysqlclient.16.dylib
libmysqlclient.16.dylib bash-3.2#
otool -L libmysqlclient.16.dylib
libmysqlclient.16.dylib:
libmysqlclient.16.dylib
(compatibility version 16.0.0, current
version 16.0.0)
/usr/lib/libSystem.B.dylib
(compatibility version 1.0.0, current
version 123.0.0)
/usr/lib/libz.1.dylib (compatibility
version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib
(compatibility version 7.0.0, current
version 7.9.0)
SOLUTION
i was add a script into build phase:
install_name_tool -change libmysqlclient.16.dylib #executable_path/../Frameworks/libmysqlclient.16.dylib $CONFIGURATION_BUILD_DIR/$PRODUCT_NAME.app/Contents/MacOS/$PRODUCT_NAME
this was fixed a libpath for executive product and working fine with lib in bundle.

First, you'll want to make sure that you're copying this library into your application bundle so that it will be available on the user's machine. To do this, add a new Copy Files build phase for your application to copy bundled frameworks. Within the properties of that build phase, make sure that the destination is Frameworks. Drag your library from your project into that build phase to make sure that it is packaged with your application.
You may also need to modify the library itself so that it points to the correct location within the application bundle. In the past, I've done this by making a copy of the library within my project's directory, then using the following command to modify where the library expects to find itself:
install_name_tool -id #executable_path/../Frameworks/libftd2xx.0.1.0.dylib libftd2xx.0.1.0.dylib
In this case, the library being modified was called libftd2xx.0.1.0.dylib.
You can use the command
otool -L [library filename]
to see the path where the library expects itself to be found and determine if this change needs to be made.
Make sure that you change the path on the library within your Xcode project so that you will be linking against this new, modified version of the library residing within your project directory.

Related

What is the simplest way to distribute an app depending on a few .dylib(s) on Mac (would zipping the .dylib(s) work)?

I built a simple app using Crystal on a Mac, and it appears to depend upon two libraries (.dylib).
What is the simplest way to distribute that app (would zipping the .dylib(s) along with the executable in a given directory work), or do I have to use a tool like install_name_tool to rewrite the path to the libraries?
In other words, if the required libraries are in the same directory than the executable, will the executable find them or is the path to libraries hard-coded in a Mac application?
otool -L ./bin/hello: yields:
./bin/hello:
/opt/homebrew/opt/bdw-gc/lib/libgc.1.dylib (compatibility version 7.0.0, current version 7.1.0)
/opt/homebrew/opt/libevent/lib/libevent-2.1.7.dylib (compatibility version 8.0.0, current version 8.1.0)
/usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)

dyld not loaded Reason: image not found libopencv_core.2.4.dylib

I'm still quite new to Objective C and Xcode, but I just finished a small app that uses the openCV libopencv_core.2.4.2.dylib.
When I went to open the final built app on another machine, OS X threw me this error:
Dyld Error Message: Library not loaded: */libopencv_core.2.4.dylib
Referenced from: /Users/USER/Desktop/my
app.app/Contents/MacOS/my app
Reason: image not found
Why is my app looking for 2.4 instead of 2.4.2 here?
What I already checked:
I added a new build phase -> so that libopencv_core.2.4.2.dylib is copied to the app package (via "Copy Bundle Resources" in Xcode) - libopencv_core.2.4.2.dylib now lies in my app.app/Resources
What did I miss? Do I have so set some more library search paths or similar?
What I also did:
install_name_tool -id "#executable_path/../Frameworks/libopencv_core.2.4.2.dylib" libopencv_core.2.4.2.dylib
Copying the dylib to the Frameworks directory doesn't work either:
Library not loaded: #executable_path/../Frameworks/libopencv_core.2.4.2.dylib
Don't know what to do now - the dylib is in the Frameworks directory of my app...
Using otool -L on the binary gives me:
/System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa (compatibility version 1.0.0, current version 19.0.0)
#loader_path/../Frameworks/libopencv_core.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
#loader_path/../Frameworks/libopencv_highgui.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
#loader_path/../Frameworks/libopencv_imgproc.2.4.2.dylib (compatibility version 2.4.0, current version 2.4.2)
/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation (compatibility version 300.0.0, current version 945.11.0)
/usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 56.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 169.3.0)
/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation (compatibility version 150.0.0, current version 744.1.0)
/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData (compatibility version 1.0.0, current version 407.7.0)
/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 1187.33.0)
I had the same problem. i keep all .dylib in system root directory usr/lib it working fine. At the run time .o file not get .dylib file path then it gives an error.
I found a better solution: recompiling openCV in Xcode and set the #executable_path/../Frameworks in the build settings, for every .dylib you compile - now the .dylibs themselves always "know where they are".
Since other answers are not clear enough;
Assume your dylib files are located in /usr/local/opt/opencv3/lib
sudo ln -s /usr/local/opt/opencv3/lib/*.dylib /usr/local/lib
will solve this problem. Be aware that /usr/lib is protected by system in MacOS, thus you should use /usr/local/lib.

Cannot create dylib for distribution that works on OS X 10.5 (building in 10.6 environment)

I'm trying to distribute cairo (1.10.2) with my application. I can create the necessarily dylibs using Homebrew but they are dependent on versions of other dynamic libraries that aren't present in OS X 10.5 (libfontconfig, libfreetype, and others located primarily in /usr/X11/lib).
I assume to solve this I want it to be using the dylibs in /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib rather than the libraries in /usr/X11/lib. I've tried anything I could find for targeting cairo against the 10.5 SDK.
Setting MACOSX_DEPLOYMENT_TARGET environment variable to 10.5 (before calling brew or using Homebrew's ENV)
Setting SDKROOT environment variable to "/Developer/SDKs/MacOSX10.5.sdk" (before calling brew or using Homebrew's ENV)
Adding -mmacosx-version-min=10.5 to the CFLAGS, CXXFLAGS, and LDFLAGS in the Homebrew formula for cairo.
Adding -sysroot/-isysroot /Developer/SDKs/MacOSX10.5.sdk to the CFLAGS, CXXFLAGS, and LDFLAGS in the Homebrew formula for cairo.
Adding -I$(SDKROOT)/usr/X11/include and -I$(SDKROOT)/usr/X11R6/include to the CFLAGS and CXXFLAGS in the Homebrew formula for cairo.
Adding -L$(SDKROOT)/usr/X11/lib and -L$(SDKROOT)/usr/X11R6/lib to the LDFLAGS in the Homebrew formula for cairo.
While building cairo it has -I/usr/X11/lib on the gcc commands (with my options tacked on the end) so I imagine it's hitting that first. I'm not sure how to get rid of that so it uses my options. I thought isysroot would make it so the include and library paths were rerooted in the SDK but -isysroot doesn't seem to have any effect.
You should be able to use install_name_tool to change where cairo looks for its libraries. (I have no idea what cairo is. I'm assuming it's a dylib. If not, my confidence in this solution goes down considerably.)
Here's a made-up example that you should be able to adapt.
First, use otool -L to see which libraries cairo is using. In this example I'm working with libopencv_imgproc.2.3.1.dylib, but you'll use your cairo library's file name instead:
$ otool -L libopencv_imgproc.2.3.1.dylib
libopencv_imgproc.2.3.1.dylib:
lib/libopencv_imgproc.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
lib/libopencv_core.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
/usr/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)
Then use install_name_tool -change to change whichever paths you need to change. The first parameter is the current library path, the second is the desired library path, and the third is the library file. I'm telling it to look for libz.1.dylib in /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/ instead of /usr/lib:
$ install_name_tool -change /usr/lib/libz.1.dylib /Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/libz.1.dylib libopencv_imgproc.2.3.1.dylib
Repeat this for every library whose path you need to change. otool -L shows us that the change was made:
$ otool -L libopencv_imgproc.2.3.1.dylib
libopencv_imgproc.2.3.1.dylib:
lib/libopencv_imgproc.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
lib/libopencv_core.2.3.dylib (compatibility version 2.3.0, current version 2.3.1)
/Developer/SDKs/MacOSX10.5.sdk/usr/X11/lib/libz.1.dylib (compatibility version 1.0.0, current version 1.2.3)
/usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.9.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)
In my example (and perhaps in your application) my library expects to find itself somewhere other than my application bundle, so I need to change that as well with install_name_tool -id. I'm copying the library to my application bundle's Frameworks folder so I'm telling it to look there:
$install_name_tool -id #executable_path/../Frameworks/libopencv_imgproc.2.3.1.dylib libopencv_imgproc.2.3.1.dylib
You can put the install_name_tool invocations in a Run Script build phase. If you are copying the library into your application bundle's Frameworks folder, you should prepend the library name with $BUILT_PRODUCTS_DIR/$FRAMEWORKS_FOLDER_PATH/ to ensure that the script can find the library.

Linking to a dynamic library on a Mac with full path

I am linking a (Python extension) library that embeds the Matlab engine with the following command (generated using cmake)
c++ -mmacosx-version-min=10.6 -bundle -headerpad_max_install_names -o library.so library.o /Applications/MATLAB_R2009b.app/bin/maci64/libeng.dylib /Applications/MATLAB_R2009b.app/bin/maci64/libmx.dylib -framework Python
resulting in
$ otool -L library.so
library.so:
#loader_path/libeng.dylib (compatibility version 0.0.0, current version 0.0.0)
#loader_path/libmx.dylib (compatibility version 0.0.0, current version 0.0.0)
/System/Library/Frameworks/Python.framework/Versions/2.6/Python (compatibility version 2.6.0, current version 2.6.1)
/opt/local/lib/gcc44/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.13.0)
/opt/local/lib/gcc44/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.0.0)
However, when I try to use the library, I get an error message:
ImportError: dlopen(./library.so, 2): Library not loaded: #loader_path/libmex.dylib
Referenced from: ./library.so
Reason: image not found
I believe the problem stems from the fact that the linker includes the matlab dylib files in the form #loader_path/libeng.dylib rather than using the full path, even though I give the full path to g++. How can I force the linker to use the full path?
I know one solution is to use
export DYLD_LIBRARY_PATH=/Applications/MATLAB_R2009b.app/bin/maci64:$DYLD_LIBRARY_PATH
which is where those library files reside, but I'd like to avoid that as it causes some other problems.
Manually changing the files using install_name_tool
install_name_tool -change "#loader_path/libeng.dylib" "/Applications/MATLAB_R2009b.app/bin/maci64/libeng.dylib" library.so
install_name_tool -change "#loader_path/libmx.dylib" "/Applications/MATLAB_R2009b.app/bin/maci64/libmx.dylib" library.so
I could use this as a temporary fix, but I wonder if there isn't a better solution where the linker is given a setting to use the full paths.
Note that some of the problems with DYLD_LIBRARY_PATH can be prevented by using DYLD_FALLBACK_LIBRARY_PATH instead. This will only be used if the lib cannot be found in the default paths.
Look into the -rpath option to the ld command to control this. You might also be interested in the contents of https://github.com/bimargulies/jni-origin-testbed, which is a demonstration of some relevant technology.
The critical technique here is:
install_name_tool -change libsl2.so "#loader_path/libsl2.so" libsl1.so
You can also use symbolic link !

dylib #executable_path path issue in a plug-in bundle

I am developing a plug-in bundle, say MyPlugIn.bundle for an application, say BigApp.app. This bundle requires a dylib, say MyPlugIn.bundle/Contents/Resources/library.dylib. I have relocated paths for library.dylib, as I would have done for a simple application bundle:
$ otool -L MyPlugIn.bundle/Contents/MacOS/MyPlugIn
MyPlugIn.bundle/Contents/MacOS/MyPlugIn:
#executable_path/../Resources/library.dylib (compatibility version 0.0.0, current version 0.0.0)
[...]
$ otool -L MyPlugIn.bundle/Contents/Resources/library.dylib
MyPlugIn.bundle/Contents/Resources/library.dylib:
#executable_path/../Resources/library.dylib (compatibility version 0.0.0, current version 0.0.0)
[...]
But BigApp.app fails to load this bundle, and Mac OS X's Console.app logs what follows:
19/01/10 15:42:59 BigApp[51516] Error loading /Library/Application Support/BigApp/Plug-Ins/MyPlugIn.bundle/Contents/MacOS/MyPlugIn: dlopen(/Library/Application Support/BigApp/Plug-Ins/MyPlugIn.bundle/Contents/MacOS/MyPlugIn, 262): Library not loaded: #executable_path/../Resources/library.dylib
Referenced from: /Library/Application Support/BigApp/Plug-Ins/MyPlugIn.bundle/Contents/MacOS/MyPlugIn
Reason: image not found
It seems that #executable_path is not replaced by the MyPlugIn.bundle executable path but by the BigApp.app executable path.
Any workaround to that, without absolute path and so that it will work on Mac OS X 10.4 (Tiger)? Thanks.
From the web and other SO questions: use #loader_path/.. instead of #executable_path/... See:
http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man1/dyld.1.html
http://lapcatsoftware.com/blog/2007/08/11/embedding-frameworks-in-loadable-bundles/
How to distribute a Mac OS X with dependent libraries?
Installing IB plugin

Resources