[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: ocaml compiled binaries and rpath



> Mmm you seem really knowledgeable on this issue, do you care to give us
> a small explanation of what the rpath is for (in the ocaml case) or
> something such, which i could then later include in the
> ocaml_packaging_policy ?

 Hhhmm. I do not _feel_ really knowledgeable on this issue at all.
 Anyway, I will try to summarize it what is our experience. I will
 also try to guess some explanations...


 First of all, let's see a minimal (but already quite involved) example:
 [ you find the code in attachment: it is made of several files and
   directories ]

*** 1 ***
 Let's start from the libA directory. Inside you will file a binding
 to a C function that implements the identity function. The function
 (in the file stub_a.c) is named fooA(). It is given the type
 string -> string in the file a.ml. Since the binding does not depend
 on any other binding (nor any other dinamically linked library), the
 Makefile is quite simple: I can just use the following command to
 build up the .cma, .cmxa and .so:

    ocamlmklib stub_a.o a.cmo a.cmx

 To make the things a bit more complex, I have added an install target
 to the makefile that installs everything in ../installed (that is by
 no means a standard library for the Linux loader).

 [ Do make && make install ]

*** 2 ***
 Let's move into the testA directory. This is a small test that uses
 the library. To compile the test, I use -I ../installed. Since I am
 not depending in any way at compile time on the .so that I have created
 in libA, the .so is not used by the compiler/linker. Thus I have just
 to say -I ../installed to tell ocaml where the .cmi/.cma files are.

 If I try to execute the output, though, the loader needs to open the .so
 ===> I get

 Fatal error: cannot load shared library dlla
 Reason: dlla.so: cannot open shared object file: No such file or directory

 To fix the problem, set LD_LIBRARY_PATH to ../installed

 [ Note that if I installed the .so in stublibs, then I would have had no
   problem at all, since the ocaml compilers hard-codes that directory
   as a loader directive. ]

 So far, so good.

*** 3 ***
 Let's move into the libB directory. Here I am doing something nasty: if
 you open stub_b.c you will see that I am using the fooA function that was
 defined in stub_a.c ==> the code that was produced is now in the .so
 file that I have installed in the non-standard ../installed path.

 Now unset the LD_LIBRARY_PATH variable and try to do make. This time
 the linker needs to know where dlla.so is! That is why I have added
 a -L../installed -la directive to ocamlmklib.  But... wait a moment!
 There is no liba.so file in ../installed! ==> I need to create in installed
 a symbolic link from dlla.so to liba.so. (Why did Xavier choose the
 dllname.so scheme? I do not know!) [ Go into ../installed and create
 the link ]

 Now that the symbolic link is in place, we can do make and get the
 library. If you look at the Makefile, I have used the following command:

 ocamlmklib -o b -L../installed -la stub_b.o b.cmo b.cmx

 Please, type it adding the -verbose flag: you will see that no -rpath
 flag is added. (Because the ../installed path is relative).

 [ We will come back to this point later. Now let's type make install and
   then let's move to the test! ]

*** 4 ***
 Let's go into testB and type Make. We get

 ocamlc -I ../libB/ -dllib dllb -o testB testB.ml
 Error on dynamically loaded library: liba.so: cannot open shared object
 file: No such file or directory
 make: *** [all] Error 2

 What is happening here? For some reason (which one???), the linker
 needs to open all the libraries required from dllb.so
 (from ../libB), i.e.  it needs to open liba.so. Unfortunately, it does
 not use the "-L../installed" flag I have used to compile the libB
 directory. Thus we are lost again. The only solution we have is to
 set LD_LIBRARY_PATH again to ../installed. Now we can do make and
 compile the file.

 Once, we get the executable, we can run it, unless we unset
 LD_LIBRARY_PATH! In we unset it, we are lost again and the loader can not
 find the library (unless it is stublibs which is hard-coded...)

*** 5 ***
 So far, so good. But where are the -rpath? Let's go back to the
 libB directory and let's issue again the ocamlmklib command with the
 -verbose flag. This time, though, use the absolute path instead of
 ../installed. This is what we get:

 claudio@oberon:/tmp/rpath/libB$ ocamlmklib -o b -L/tmp/rpath/installed -la
 stub_b.o b.cmo b.cmx -verbose
 + gcc -shared -o dllb.so stub_b.o -L/tmp/rpath/installed
 -Wl,-rpath,/tmp/rpath/installed -la
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 + ar rc libb.a stub_b.o
 + ranlib libb.a
 + /usr/bin/ocamlc -a  -o b.cma  b.cmo -dllib -lb -cclib -lb -ccopt
 -L/tmp/rpath/installed -ccopt -Wl,-rpath,/tmp/rpath/installed -cclib -la 
 + /usr/bin/ocamlopt -a -o b.cmxa  b.cmx -cclib -lb -ccopt
 -L/tmp/rpath/installed -ccopt -Wl,-rpath,/tmp/rpath/installed -cclib -la 

 Xavier decided to add a -rpath option (it does so every time the -L is
 followed by an absolute path). What is the gain? Type "make install"
 and let's go back to testB. Unset LD_LIBRARY_PATH and try make again.
 THIS TIME IT WORKS! The -rpath tells the linker where the library is
 to be found! Thus we do not need to use LD_LIBRARY_PATH in any way.
 [ That's good! ]

 Still, let's try to execute testB: it does not work!!! The -rpath is
 used only by the linker, not by the loader!



**************************

 To sum up: Xavier decided to use the -rpath trick to avoid setting
 LD_LIBRARY_PATH when linking. Instead he hard-coded the stublibs
 directory in the produced code, so that the loader does not complain.
 One trick is for the linker, the other one for the loader.
 The second trick works only for the stublibs directory. The first one
 always work (but makes lintian complain). Moreover there is also the
 symbolic link trick from dllname.so to libname.so that should be done
 by hand.

 What happens if you remove the -rpath from a debian package? You may
 break the compilation processes of other people that are expecting
 your library to have the -rpath and that do not have the LD_LIBRARY_PATH
 set to stublibs (or other strange directories).

 Final note: of course the problem solved by rpath was much more critical
 _before_ the introduction of the single stublib directory (those times
 when my LD_LIBRARY_PATH used to be several lines long).


 I hope that all this could be useful to somebody: my wirst is aching!

 						Cheers,
						C.S.C.

-- 
----------------------------------------------------------------
Real name: Claudio Sacerdoti Coen
PhD Student in Computer Science at University of Bologna
E-mail: sacerdot@cs.unibo.it
http://www.cs.unibo.it/~sacerdot
----------------------------------------------------------------

Attachment: rpath.tgz
Description: GNU Unix tar archive


Reply to: