[CMake] Weirdness with shared library, RPATH policy on MacOS

Michael Wild themiwi at gmail.com
Sat Aug 14 16:01:53 EDT 2010


On 14. Aug, 2010, at 18:26 , Chris Wolf wrote:

> 
> 
> On 8/14/10 10:31 AM, Michael Wild wrote:
>> 
>> On 14. Aug, 2010, at 15:13 , Chris Wolf wrote:
>> 
>>> 
>>> 
>>> On 8/14/10 3:35 AM, Michael Wild wrote:
>>>> 
>>>> On 13. Aug, 2010, at 20:58 , Michael Wild wrote:
>>>> [...]
>>>>> 
>>>>> Sure, http://repo.or.cz/w/freefoam.git/shortlog/refs/heads/pu, but it's pretty complex...
>>>>> 
>>>>> Michael
>>>> 
>>>> Attached is a tiny project which works for me on both Linux and Mac.
>>>> 
>>>> Michael
>>>> 
>>> 
>>> That's awesome! Thanks so much.  From your example, and looking at the documentation:
>>> http://www.cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH
>>> 
>>> ...I can see the difference now - you are setting CMAKE_INSTALL_NAME_DIR. 
>>> (which is not needed or used on Linux/ELF)
>>> 
>>> What I had been trying to do along these lines was a per-target setting:
>>> 
>>> set_target_properties(usbDynamic PROPERTIES INSTALL_NAME_DIR "/tmp/local/lib")
>>> 
>>> -=or=-
>>> 
>>> set_target_properties(usbDynamic PROPERTIES INSTALL_RPATH "/tmp/local/lib/libusb-1.dylib"")
>>> 
>>> -=or=-
>>> 
>>> set_target_properties(usbDynamic PROPERTIES
>>>  INSTALL_RPATH "/tmp/local/lib/libusb-1.dylib"
>>>  INSTALL_NAME_DIR "/tmp/local/lib")
>>> 
>>> None of those were working for me.
>>> 
>>> I will incorporate your setting in my project.
>>> 
>>> Thanks,
>>> 
>>>  -Chris
>> 
>> 
>> Aaaah, I see. The INSTALL_RPATH should have been /tmp/local/lib. And RPATH is only a Linux thing, while install_name is a Mac OS X thing ;-)
>> 
>> Michael
> 
> Actually, "/tmp/local/lib" is just for testing - my intention is to use "/usr/local/lib".
> 
> Also RPATH on Mac OSX is no different then Linux, SunOS, etc. - only the mechanism to change it is.
> 
> For example, CMake appears to use perform direct modification of ELF-formatted binaries, 
> apparently to avoid relinking upon installation (i.e. running the generated cmake_install.cmake)
> 
> It does this via the undocumented FILE(RPATH_CHANGE,.., FILE(RPATH_REMOVE,... routines.
> which are called indirectly via 
> cmInstallTargetGenerator::PostReplacementTweaks/cmInstallTargetGenerator::AddChrpathPatchRule
> 
> For some reason (maybe to accommodate frameworks) instead of polymorphically implementing
> cmSystemTools::ChangeRPath and cmSystemTools::RemoveRPath to handle the ELF *or* Darwin
> cases (which would have allowed AddChrpathPatchRule to work for ELF *and* Darwin) 
> - a separate piece of logic was implemented for PostReplacementTweaks called,
> cmInstallTargetGenerator::AddInstallNamePatchRule, which invokes the OSX utility
> "install_name_tool" to change the RPATH in shared libraries and executables.
> 
> The way I see it (and I could be wrong) there is divergence between the logic of
> AddChrpathPatchRule (ELF RPATH logic) and AddInstallNamePatchRule (Darwin RPATH logic)
> 
> Ideally, if cmSystemTools::ChangeRPath and cmSystemTools::RemoveRPath  were 
> polymorphic for ELF and Darwin, you would only need AddChrpathPatchRule and not
> AddInstallNamePatchRule, such that the FILE(RPATH_CHANGE,.., FILE(RPATH_REMOVE
> routines would function the same for ELF and Darwin and the generated
> "cmake_install.cmake" would look the same for both of these platforms - as a result,
> the documented behavior (http://www.cmake.org/Wiki/CMake_RPATH_handling)
> would be identical for ELF and Darwin cases.
> 
> Well, that's my two cents...
> 
> Thanks again for your help,
> 
>  -Chris

No, the two mechanisms are fundamentally different.

On Linux the RPATH is a search path (think LD_LIBRARY_PATH) that is encoded into the binary. The linker only embeds the library name, no directory information. The loader then first searches these directories for the linked libraries, and then proceeds to search LD_LIBRARY_PATH and the directories defined in ld.conf.

On Mac OS X, the install_name is a file name encoded into the library itself. When another binary is linked against this library, the linker hard-codes this file name into the binary, no matter what the actual location of the library is. The loader then tries to load that library using the hard-coded install_name from the binary, and only if that fails, uses DYLD_FALLBACK_LIBRARY_PATH.

I hope this clarifies things a bit.

Michael


More information about the CMake mailing list