Subject: Re: "-Ldir -lname" vs. "dir/libname.so"
To: Johnny Lam <jlam@jgrind.org>
From: Todd Vierling <tv@wasabisystems.com>
List: tech-toolchain
Date: 03/13/2002 17:10:48
On Wed, 13 Mar 2002, Johnny Lam wrote:

: I was able to test on a NetBSD-1.5.1/mac68k machine, and they do both
: generate the shared library libbar.so.0.0; however, I'm not sure how to
: tell what ware the interlibrary dependencies recorded in libbar.so.  On
: the ELF system, I was able to run "ldd libbar.so" and discover the
: dependencies, but that doesn't work on the a.out system.  Do I have to
: link an executable against libbar.so and run "ldd" on the executable to
: discover the dependencies?

Yes, you have to run ldd on a program linked with libbar.so.

===

: > FROM MEMORY ONLY, may be incorrect:  The a.out linker, in case (a), will
: > encode a major number and minimum minor number for use by the runtime
: > linker.  However, if a full filename as in case (b) is given with
: > .major.minor, only that specific library pathname will be usable -- any
: > library with an incremented minor number will not link.
:
: Given how pkgsrc works, that would be bad.  I'll try some tests on the mac68k,
: but will those results be representative for all NetBSD/a.out platforms?

Yes, all a.out platforms have the same semantics.  As I said, this could all
be wrong and from memory of linker stupidity in very early pkgsrc, but
there's faint bells ringing when I noted this.

===

: It involves the interaction between libtool and buildlink.  When a package
: uses libtool to create two shared libraries libbar.so and libfoo.so, one
: depending on the other as above, and then uses libtool to install them into
: /usr/pkg/lib, then libbar.so is relinked prior to the actual installaion so
: that it can find libfoo.so in /usr/pkg/lib.

Is this buildlink or libtool that does the relinking?  If buildlink, then
libtool is broken and needs to be fixed (since the package with libtool
won't work out-of-the-box).  In either case, relinking the binaries is
completely unnecessary for NetBSD, as well as any other ELF-compliant
system.

The correct way to record a dependency while everything is still in a build
tree goes something like below, where a program and libraries are being
linked in a dependency tree "prog -> libbar -> libfoo -> libsomelib".

Here, I'm presuming that libfoo is going in /usr/pkg/foo/lib, and libbar in
/usr/pkg/bar/lib (so that you understand which -Rs and -Ls point to what
library).  -lsomelib is assumed already installed in /usr/pkg/some/lib.

==========
[ELF]

	cd libfoo
	cc -shared -o libfoo.so.0.0 -Wl,-soname,libfoo.so.0 ... \
		-R/usr/pkg/some/lib -L/usr/pkg/some/lib -lsomelib
	ln -s libfoo.so.0.0 libfoo.so.0
	ln -s libfoo.so.0.0 libfoo.so

	cd ../libbar
	cc -shared -o libbar.so.0.0 -Wl,-soname,libbar.so.0 ... \
		-R/usr/pkg/foo/lib -L../libfoo -lfoo \
		-Wl,-rpath-link,/usr/pkg/some/lib

	cd ../prog
	cc -o prog ... \
		-R/usr/pkg/bar/lib -L../libbar -lbar \
		-Wl,-rpath-link,/usr/pkg/some/lib \
		-Wl,-rpath-link,../libfoo

[a.out]

	cd libfoo
	ld -Bshareable -o libfoo.so.0.0 ... \
		-R/usr/pkg/some/lib -L/usr/pkg/some/lib -lsomelib

	cd ../libbar
	ld -Bshareable -o libbar.so.0.0 ... \
		-R/usr/pkg/foo/lib -L../libfoo -lfoo

	cd ../prog
	cc -o prog ... \
		-R/usr/pkg/bar/lib -L../libbar -lbar
==========

Above, "..." is the list of objects for each binary.

You'll note that a.out doesn't need anything special, but that's because the
a.out linker is actually *missing* the recursion logic for dependencies (it
assumes that -l arguments are linked properly, and lets ld.so sort out the
dependency logic).

But under ELF, the situation is different:  the linker searches for the
dependencies.  While the rpaths are provided above, there's no way to know
how to find the dependencies at link time without *another* option (ld's
-rpath-link option, to be exact).

If -rpath-link is properly specified, there is no reason to relink anything
at all.  That option allows ld(1) to find all the dependencies when doing an
ELF link, without recording those temporary paths into the binary.

===

: 		/usr/lib/libssl.so		[system supplied ]
: 		/usr/lib/libcrypto.so		[  OpenSSL-0.9.5a]
:
: 		/usr/pkg/lib/libssl.so		[pkgsrc-supplied ]
: 		/usr/pkg/lib/libcrypto.so	[  OpenSSL-0.9.6b]
:
: 	libbar.so explicitly needs the old OpenSSL libraries, and has
: 	the following dependencies:
:
: 		libbar.so: /usr/pkg/lib/libfoo.so.0.0
: 		           /usr/lib/libssl.so.?.?
: 		           /usr/lib/libcrypto.so.?.?
:
: 	The relink command for libbar.so does:
:
: 		cc -shared -Wl,-soname -Wl,libbar.so.0 -o libbar.so.0.0 \
: 			-L/usr/pkg/lib -lfoo -lssl -lcrypto
:
: But this relink command will link against the wrong OpenSSL libraries.

What does the original (non-relink) command for libbar do?  (Under the
assumption, as above, that relinking should not actually be necessary.)

Basically, if you have "-Wl,-rpath-link,/usr/pkg/lib" in the above, you
should end up with the pkgsrc libssl and libcrypto, rather than the
system-supplied version.  ld will use that rpath-link directory to find the
expected dependencies of libfoo.

===

: If instead, it executed:
:
: 		cc -shared -Wl,-soname -Wl,libbar.so.0 -o libbar.so.0.0 \
: 			/usr/pkg/lib/libfoo.so -lssl -lcrypto
:
: then I could control which libraries to link against more accurately.

Wouldn't this break you even further?  With no -L or -R at all, you'll link
against the system-supplied ssl/crypto libraries for sure, not the
pkgsrc-supplied ones.  And given that libfoo.so is in /usr/pkg/lib, why
would you want to assume that the system-supplied versions are the correct
ones?

-- 
-- Todd Vierling <tv@wasabisystems.com>  *  Wasabi & NetBSD:  Run with it.
-- CDs, Integration, Embedding, Support -- http://www.wasabisystems.com/