HEAD doesn't build (was Re: patch applied (ghc): Add hardwire-lib-paths option and make it default for inplace invocations)

R Hayes rfhayes at reillyhayes.com
Wed Aug 1 20:21:19 EDT 2007


I think there is some misinformation in here, as well as some correct  
but misleading information.  Some of the documentation is dodgy, so I  
have taken the time to verify my assertions on my Mac (Intel OS X  
10.4.10) and my linux box (Linux 2.6.15 X86_64).

I will reiterate what I understand the goals to be:

1) When creating an executable, specify where the dynamic loader  
should look for shared libraries at runtime.  The intent is to expand  
the shared library search space beyond the default search path and  
remove the need to set environment variables.

2) When running an executable, override the default.  Primarily a  
requirement for building GHC.

On Linux
------------

An ELF executable can have an embedded list of paths to search for  
dynamic libraries (the DT_RPATH entry).  This can be set by using - 
rpath with ld.  DT_RPATH is deprecated.  This list applies to all  
shared libraries used by the executable (it is not per shared  
library).  There is no default value placed in the DT_RPATH entry.   
You must use -rpath to set it.

There is a new entry, DT_RUNPATH.  DT_RUNPATH works similarly to  
DT_RPATH.  However, when it is set, DT_RPATH is ignored.  DT_RUNPATH  
is also set using -rpath, but you must use the --enable-new-dtags  
switch as well.

When looking for a shared library, the dynamic linker(ld.so) checks  
the paths listed in DT_RPATH (unless DT_RUNPATH Is set) , the paths  
listed in the environment variable LD_LIBRARY_PATH, the paths listed  
in DT_RUNPATH, the libraries listed in /etc/ld.so.cache, and finally / 
usr/lib and /lib.  It checks in that order and takes the first  
library found.  At least on my linux box, LD_LIBRARY_PATH does NOT  
override the paths in DT_RPATH even though the documentation implies  
that it does.   LD_LIBRARY_PATH does override DT_RUNPATH.

You CAN override the search path embedded using DT_RPATH by using the  
LD_PRELOAD environment variable.  This variable contains a  
*whitespace-separated* list of libraries (not directories to search)  
to load prior to the search process.  The listed libraries are loaded  
whether or not they are needed to resolve a dependency in the  
executable.

Finally, an ELF shared library can also have a DT_RPATH entry.  This  
only impacts the search for shared libraries that are dependencies of  
the shared library and not the executable.  As with the DT_RPATH  
entry in an ELF executable, this is not overridden by LD_LIBRARY_PATH  
but can be overridden using LD_PRELOAD as above.

On Mac OS X
------------------

A Mach-O executable can embed the full path name for each shared  
library (as well as rules for acceptable substitutes).  This is  
called the "install name" for the library and it is included by  
default when building an executable.  The install name for the  
library is NOT based on where the static linker (ld) found the  
library when the executable was built.  The static linker (ld)  
extracts the install name from the shared library when building the  
executable.  The install name of the shared library is set when  
building the shared library.  When you build a shared library you  
should know where the library is going to be installed so that the  
install name is set correctly.

When looking for shared libraries, the dynamic linker (dyld) first  
scans the directories in DYLD_LIBRARY_PATH, then checks the location  
in the install name (which is per library), and finally checks the  
standard locations.

DYLD_LIBRARY_PATH successfully overrides the the path embedded in the  
executable.

Caveat 1: LD_LIBRARY_PATH has no runtime impact, but it does impact  
where the static linker looks for share libraries.  It looks first in  
the directories specified using -L, the the directories in  
LD_LIBRARY_PATH, and finally in /lib, /usr/lib, & /usr/local/lib.   
This is particularly confusing  because many configure scripts seem  
to ignore LD_LIBRARY_PATH and you can get inconsistent results from  
configure and gcc/ld on whether a library is present.

Caveat 2: Mac OS X has a set of compiler/linker switches for dealing  
with Frameworks (packages of shared libraries and include files).   
These are installed outside the typical *nix directory structure.   
These switches act like -I (to gcc) and -L (to ld).  If you end up  
totally confused about where to find something, read up on this.  The  
OpenGL and OpenAL headers and libraries are in Frameworks, for example.

My Conclusions
-----------------------

For Mac: The -rpath switch is not available on Mac OS X because it is  
superfluous.  The default behavior of embedding a location for each  
individual shared library is at least as good.  Cabal (and the GHC  
build process) should use their knowledge of the ultimate install  
location to set the install name when shared libraries are built.  In- 
place compilation can override this with DYLD_LIBRARY_PATH

For Linux: On linux, we should be sure to use the --enable-new-dtags  
switch if we use -rpath.  Otherwise we risk having paths that can't  
be overridden by LD_LIBRARY_PATH.  I know we don't want to have an  
install that *requires* root access, but we should consider adding  
entries to /etc/ld.so.conf and running ldconfig to eliminate the need  
to hardwire path names.

Verification
---------------

I wrote a small but heinous C program that called a trivial function  
in a shared library.  Using 2 copies of the shared library, I  
observed which was used under the various scenarios.

On linux, I used "objdump -p" to examine the ELF executables and  
shared libraries.  I used "ldd" to see which libraries were actually  
being loaded.  When I got an unexpected result from ldd  
(LD_LIBRARY_PATH not overriding DT_RPATH), I went so far as using  
lsof on the process to see which files were mapped.

On the Mac, I used "otool -l" to examine the Mach-O executables and  
shared libraries.  I used the environment variable  
DYLD_PRINT_LIBRARIES=YES to see which libraries were actually being  
loaded (this forces dyld to print the location of each library as it  
is loaded).

--Reilly Hayes



On Aug 1, 2007, at 6:36 AM, Simon Marlow wrote:

> Roman Leshchinskiy wrote:
>> Simon Marlow wrote:
>>> Roman Leshchinskiy wrote:
>>>> Simon Marlow wrote:
>>>>> Roman Leshchinskiy wrote:
>>>>>> Simon Marlow wrote:
>>>>>>>
>>>>>>> We had a discussion on glasgow-haskell-users recently about  
>>>>>>> whether to use libtool, and the general concensus was not:
>>>>>>
>>>>>> Hmm, I missed that one completely. It's probably too late for  
>>>>>> me to jump in but I just don't see how the approach you  
>>>>>> outlined in
>>>>>>
>>>>>> http://www.haskell.org/pipermail/glasgow-haskell-users/2007- 
>>>>>> June/012740.html
>>>>>>
>>>>>> deals with systems which don't *have* an rpath and with users  
>>>>>> who manually set LD_LIBRARY_PATH. To be entirely honest, I  
>>>>>> suspect that what you are trying to achieve can't be done  
>>>>>> portably and reliably.
>>>>>
>>>>> I don't expect it to be portable.  So on MacOS X, is it the  
>>>>> case that the only way to build a binary that links to a  
>>>>> particular shared library outside the system location is to use  
>>>>> LD_LIBRARY_PATH?
>>>>
>>>> IIUC yes, except that it's called DYLD_LIBRARY_PATH. From man dyld:
>>>>
>>>>   For  each  library that a program uses, the dynamic linker looks
>>>>   for it in each directory in DYLD_LIBRARY_PATH  in  turn.  If  it
>>>>   still  can't  find  the  library,  it  then  searches DYLD_FALL-
>>>>   BACK_FRAMEWORK_PATH and DYLD_FALLBACK_LIBRARY_PATH in turn.
>>>>
>>>> But I think on MacOS, the library paths are usually hardcoded in  
>>>> the executable.
>>>
>>> If you can hardcode the library paths in the executable, then  
>>> that's exactly what -rpath does isn't it?
>> After looking at the documentation I think I sort of understand  
>> how the system works. When you build a shared library you can  
>> specify its install_name which is the location where it will  
>> ultimately be installed. When linking against the library, the  
>> linker hardcodes the library's install_name into the executable.  
>> When the executable is run, the dynamic loader looks for the  
>> library at that location. If it finds the library, it's happy. If  
>> not, it will (appently) look in DYLD_LIBRARY_PATH and friends and  
>> then in standard locations (/usr/lib etc.) but will ignore  
>> DYLD_LIBRARY_PATH for setuid and setgid processes.
>
> It sounds like the only way to get the effect of -rpath is to  
> create a wrapper script that sets DYLD_LIBRARY_PATH, then.   
> Presumably this is what libtool does.
>
> This is a bit of a pain.  We can't support -hardwire-lib-paths on  
> MacOS, and we'll need some jiggery-pokery in the build system to  
> get the same effect - perhaps ghc-inplace sets DYLD_LIBRARY_PATH  
> before invoking the ghc binary.
>
> Cheers,
> 	Simon
>
> _______________________________________________
> Cvs-ghc mailing list
> Cvs-ghc at haskell.org
> http://www.haskell.org/mailman/listinfo/cvs-ghc

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/cvs-ghc/attachments/20070801/ccf43a56/attachment-0001.htm


More information about the Cvs-ghc mailing list