Subject: packages, rpaths, compat, oh my!
To: None <netbsd-help@netbsd.org>
From: Richard M Kreuter <kreuter@progn.net>
List: netbsd-help
Date: 09/18/2004 18:00:26
Hello,

I'm running a few NetBSD 1.6 and 2.0 beta hosts, and would like to
share /usr/pkg and /usr/local across all of them. The 2.0 hosts'
kernels have COMPAT_16 enabled, and have the compat16 package
installed, but programs that require library versions from NetBSD 1.6
don't run without help, because nothing causes those programs to use
the libraries in /usr/pkg/emul/netbsd16. [1]

I'm reluctant to maintain separate sets of binaries for the two
versions, and I'll probably have to keep the 1.6 hosts around for a
bit, so I tried to solve the problem by using rpaths. By inspection,
adding the relevant lib directories under emul/netbsd16 to the rpath
in CFLAGS/LDFLAGS at compile time can produce executables that will
work as desired on both the 1.6 and 2.0 hosts. This works for several
programs I build manually (without pkgsrc), but somehow executables
created by pkgsrc packages don't get the additional directories in
their rpaths at link time, even though the link command includes the
relevant rpath directives, and even though running the same link
command manually in the same package's work directory yields an
executable with the desired rpath.

screen is a good example. If I run the following command in
pkgsrc/misc/screen, the executable doesn't get the rpath I want:

$ LDFLAGS="-Wl,-R/emul/netbsd16/usr/lib" make
=> Checksum OK for screen-4.0.2.tar.gz.
<snip>
gcc -Wl,-R/emul/netbsd16/usr/lib -Wl,-R/usr/pkg/lib -o screen screen.o ansi.o fi
leio.o mark.o misc.o resize.o socket.o  search.o tty.o term.o window.o utmp.o lo
adav.o putenv.o help.o  termcap.o input.o attacher.o pty.o process.o display.o c
omm.o  kmapdef.o acls.o braille.o braille_tsi.o logfile.o layer.o  sched.o teln.
o nethack.o encoding.o utmp-netbsd.o -lcurses  -lutil -lutil -lcrypt
=> Fixing buildlink references in files-to-be-installed.
$ readelf -d work/screen-4.0.2/screen

Dynamic segment at offset 0x43214 contains 21 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libcurses.so.5]
 0x00000001 (NEEDED)                     Shared library: [libutil.so.6]
 0x00000001 (NEEDED)                     Shared library: [libcrypt.so.0]
 0x00000001 (NEEDED)                     Shared library: [libc.so.12]
 0x0000000f (RPATH)                      Library rpath: [/usr/pkg/lib]
 0x0000000c (INIT)                       0x80499bc
 0x0000000d (FINI)                       0x80811b4
 0x00000004 (HASH)                       0x8048124
 0x00000005 (STRTAB)                     0x8048f68
 0x00000006 (SYMTAB)                     0x80485a8
 0x0000000a (STRSZ)                      1350 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x808bfbc
 0x00000002 (PLTRELSZ)                   1104 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8049508
 0x00000011 (REL)                        0x80494b0
 0x00000012 (RELSZ)                      88 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000000 (NULL)                       0x0

However, if I re-run the same link command, it does what I want:

$ cd work/screen-4.0.2/
$ gcc -Wl,-R/emul/netbsd16/usr/lib -Wl,-R/usr/pkg/lib -o screen screen.o ansi.o fileio.o mark.o misc.o resize.o socket.o  search.o tty.o term.o window.o utmp.o loadav.o putenv.o help.o  termcap.o input.o attacher.o pty.o process.o display.o comm.o  kmapdef.o acls.o braille.o braille_tsi.o logfile.o layer.o  sched.o teln.o nethack.o encoding.o utmp-netbsd.o -lcurses  -lutil -lutil -lcrypt
$ cd -
/usr/pkgsrc/misc/screen
$ readelf -d work/screen-4.0.2/screen

Dynamic segment at offset 0x43214 contains 21 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [libcurses.so.5]
 0x00000001 (NEEDED)                     Shared library: [libutil.so.6]
 0x00000001 (NEEDED)                     Shared library: [libcrypt.so.0]
 0x00000001 (NEEDED)                     Shared library: [libc.so.12]
 0x0000000f (RPATH)                      Library rpath: [/emul/netbsd16/usr/lib:/usr/pkg/lib]
 0x0000000c (INIT)                       0x80499cc
 0x0000000d (FINI)                       0x80811c4
 0x00000004 (HASH)                       0x8048124
 0x00000005 (STRTAB)                     0x8048f68
 0x00000006 (SYMTAB)                     0x80485a8
 0x0000000a (STRSZ)                      1373 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x808bfbc
 0x00000002 (PLTRELSZ)                   1104 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8049520
 0x00000011 (REL)                        0x80494c8
 0x00000012 (RELSZ)                      88 (bytes)
 0x00000013 (RELENT)                     8 (bytes)
 0x00000000 (NULL)                       0x0

I'm kinda confused about this result. Can anybody tell me how to get
pkgsrc to do this (presumably unusual) thing for executables?

Thanks in advance,
Richard Kreuter

[1] At any rate, I don't know of a good way to get the executables to
use those libraries. Unlike the COMPAT_* emulations of other operating
systems, it doesn't look like there's any magical pathname magic going
on when running old native binaries on NetBSD; I don't know whether
there's any version information in the binaries to indicate that a
native binary is old. I'd prefer not to litter /usr/lib and
/usr/X11R6/lib with symlinks, since eventually I won't need the old
libraries any more. Wrapping some of the failing programs with scripts
that set LD_LIBRARY_PATH can work, but there are some suid programs
that I'd like to use (e.g., screen, minicom), and even for programs
that can work this way, having old versions of the libraries in
directories in LD_LIBRARY_PATH prevents running 2.0 binaries as
subprocesses. Using rpaths seems to be an elegant solution, at any
rate.