Does anybody have a good tutorial handy on embedding libclang in a Cocoa app?
In particular I get issues with the rpath at launch saying the dylib couldn't be found.
Error was the lovely
dyld: Library not loaded: #rpath/libclang.dylib
What this error is sadly trying to tell you is that lib clang thinks its #rpath is at the root of your app bundle, but it's not.
I figured this out the hard way just the other day.
It's hard.
You have to do some crazy stuff with libclang.a using Build Phase settings.
In your target's Build Phases, you will need to add a few Run Script Phases.
One will be this:
echo "warning: OTOOL BEGIN1";
pwd;
otool -L ${SRCROOT}/Clangwrap/ClangAndLLVM/lib/libclang.dylib;
echo "Warning: OTOOL END1";
This just does a few things.
First it nicely sandwiches things with a log to see what happened.
The second is it really is just confirming the path to your lib once it's copied. (and yes, you should be copying it into your project to keep things sane.)
otool does this.
SRCROOT is the root of your project, then anything after that is your relative path within you project's folder in Finder to the lib you are going to use.
Again, this just confirms it is where you think it is.
Ok, next step. This is the real doozy.
echo "BEGIN install_name_tool";
install_name_tool -id #executable_path/../Frameworks/libclang.dylib ${SRCROOT}/Clangwrap/ClangAndLLVM/lib/libclang.dylib;
echo "END install_name_tool";
This runs the obscure command line tool install_name_tool and that is used to set the path where the lib thinks it is located within your app's bundle. Without doing this, the lib will think it is in some other path. You will be setting this path to what you intend it to be. In a Mac app, I used the Frameworks folder inside the bundle so I set it as such. The first argument to install_name_tool is the relative path in your app bundle where the lib is going to be. The second argument is where the lib is currently in your project so that install_name_tool can set its executable path.
This literally modifies a bit of the lib so it is loadable. libs must know their own load path.
Note the first step is only optional for your own sanity.
The second step is required, and both should occur before the Compile Sources Build Phase.
Click and drag to move them up.
Now the final step. Add a new Copy Files Phase and this will remain last in your build phases.
Set the destination to the same as the first arg of install_name_tool so you know your relative path is set and that's where you're going to put the lib.
I used Frameworks.
Now add the files to this Build Phase, for iPhone, add libclang.a (I don't think you can use libclang.dylib on iOS)
Note, you saw me use libclang.dylib and that's because I did this on a Mac app project. It should be the same process for just about anything.
this is not an easy or discoverable process, I pieced it together from several blogs and docs.
Related
I have a project in Xcode where I set DYLD_FALLBACK_LIBRARY_PATH in the environment variables pane to set where my application should look for libraries to link to (which works well for my purposes)
I am writing a CMakeLists.txt file to generate this project now and I would like to set this property from the script.
I am aware I can do this:
SET(ENV{DYLD_FALLBACK_LIBRARY_PATH} ${DYLD_FALLBACK_LIBRARY_PATH} /path/to/lib)
but when I run I get this error:
'dyld: Library not loaded ... Reason: image not found'
when launching the application. I imagine the statement is not the same.
Does someone know how I can achieve the equivalent of what I have in Xcode from CMakeLists.txt?
I am vaguely aware of the CMake RPATH stuff but I'd rather avoid that if possible.
Thank you for your time!
Cheers!
Tom
I did finally get this working using a slightly different approach. This might not be the perfect solution and work in all cases, but hopefully this will help someone who is having similar problems to me.
The dylib I was trying to link to was libSDL2-2.0.0
If I navigate to where that file is located and run:
otool -L libSDL2-2.0.0.dylib
the top line I get in the output is this:
/usr/local/lib/libSDL2-2.0.0.dylib
if I then navigate to my built executable and run the same command, I see the same thing:
/usr/local/lib/libSDL2-2.0.0.dylib
(my executable links to SDL)
My problem was libSDL2-2.0.0.dylib is not actually located there, it's in my project structure in a libs folder. In order to get the linker to find the lib at runtime, I had to run this command on the dylib
install_name_tool -id "#executable_path/../path/to/lib/<lib_name>" <lib_name>
where #executable_path is the location of the application to run - in my case this was in - build/debug
The project structure:
root/
CMakeLists.txt
project/
lib/
libSDL2-2.0.0.dylib
build/
debug/
my_app
This is an exact mapping for clarity:
install_name_tool -id "#executable_path/../../project/lib/libSDL2-2.0.0.dylib" libSDL2-2.0.0.dylib
If I run otool -L libSDL2-2.0.0.dylib I now see:
#executable_path/../../sdl-test/lib/libSDL2-2.0.0.dylib
in the first line of the output.
If I now build my project again (I'm just building in Xcode), this updates my app with the new relative path to the dylib. You only have to run install_name_tool on the library, you do not also have to run it on your executable, it will be updated when you build it.
If I run otool -L myapp I now see the same relative path to libSDL2-2.0.0.dylib
With that, when launching the app it was able to successfully find the dylib!
My understanding is that this is the way to achieve this on OSX and there isn't a brilliant alternative (other than messing with DYLD_FALLBACK_LIBRARY_PATH which I mentioned in my question)
I hope this has been of some help to someone who had similar difficulties to me!
Resources I found useful:
http://osiris.laya.com/coding/dylib_linking.html
https://www.fmod.org/questions/question/forum-23398/
https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac
UPDATE:
I actually found an even better way to do this using rpaths and thought I'd write up how to do this for future reference:
In my CMakeLists.txt file I added these lines right at the end (after ADD_EXECUTABLE and TARGET_LINK_LIBRARIES:
# set #rpaths for libraries to link against
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
SET(CMAKE_INSTALL_RPATH "${PROJ_LIB_DIR}")
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
(see https://cmake.org/Wiki/CMake_RPATH_handling for more info)
where ${PROJ_LIB_DIR} is where my dylibs are located:
SET(PROJ_LIB_DIR ${CMAKE_CURRENT_LIST_DIR}/lib)
I then ran:
example:
install_name_tool -id "#rpath/<my-dylib>.dylib" <my-dylib>.dylib
actual:
install_name_tool -id "#rpath/libSDL2-2.0.0.dylib" libSDL2-2.0.0.dylib
in the directory where my dylib is located (in my case libSDL2-2.0.0.dylib)
Now when I run cmake and then build my project, my new executable will search for the library in the location I set in the CMakeLists.txt file at runtime. #rpath will be substituted with the path specified in the CMakeLists.txt file and everything just works without explicitly having to set the #executable_path or #loader_path
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.
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
I am new to Xcode and Mac environment. I am using some dynamic and static libraries like boost, Clucene, etc. I have all the libraries under
MyApp.app/Contents/Resources
I want to set this path as the app's dyld_library_path. I tried editing XXX.plist file like
DYLD_LIBRARY_PATH /mypath/xxx
and setting the environment variable and argument in Xcode Nothing work.
but if I run a shell script like below without double clicking the app in my .dmg it works
#!/bin/bash
clear
cd /Volumes/xxx/myapp.app/Contents/MacOS
export DYLD_LIBRARY_PATH="/Volumes/xxx/myapp.app/Contents/Resources"
./myapp
I am sure this is not the proper way to do this. Is there proper way to set dyld_library_path every time I execute my app?
EDIT:
It also works if u mannualy copy all ur library to clients /usr/lib path... i guess this is also not a proper way to do it.
Setting DYLD_LIBRARY_PATH isn't the best way to solve this problem. It's working around the fact that you've misinformed dyld as to where to find your libraries.
If you run otool -L MyApp.app/Contents/MacOS/MyApp you'll see the paths to the libraries that MyApp wants to load. If any library isn't found at the specified path then dyld will look for the library in the locations specified by DYLD_FALLBACK_LIBRARY_PATH. Setting DYLD_LIBRARY_PATH causes dyld to look for the library in the given locations ahead of the path that the otool command above returned.
The best way to solve this problem is to have your application specify the correct location of the libraries to start with so that setting DYLD_LIBRARY_PATH is not necessary. To do this you need to do the following:
Set the library identifier of each of the libraries that you're bundling inside your application to an #rpath-relative value. You can do this using install_name_tool -id #rpath/libFoo.dylib libFoo.dylib.
Add a Copy Files build phase to copy the libraries in to your application wrapper. MyApp.app/Contents/Frameworks is a typical location. MyApp.app/Contents/Resources should be avoided since binaries aren't resources in the usual sense of the term.
Specify a run path search path when linking your application. This gives the linker a list of paths to use to resolve any #rpath variables that it encounters in any load commands. If you're copying the libraries to MyApp.app/Contents/Frameworks you'll want to specify a run path search path of #loader_path/../Frameworks. You can do this via the LD_RUNPATH_SEARCH_PATHS (Runpath Search Paths) configuration setting in Xcode on your application target.
After doing all this you should be able to re-run the otool command mentioned above and see that the paths to your library are using #rpath-relative paths. You should then be able to run otool -lV MyApp.app/Contents/MacOS/MyApp and see an LC_RPATH load command specified with a value of #loader_path/../Frameworks. Finally, you should be able to run your application and see that it finds the libraries within its Frameworks directory without having DYLD_LIBRARY_PATH set!
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?