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