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