On 29 Apr 2012, Darrell Anderson uttered the following:
Do I need to add /opt/trinity/lib/trinity too or are
subdirectories of /opt/trinity/lib automatically found by ldconfig?
No, you need to add any directory outside the 'standard system set' (normally /usr/local/lib, /usr/lib, /lib, and any /lib32 / /lib64 variants your distro may use). Subdirectories are not autoamtically searched to satisfy DT_NEEDED entries. However, the lib/trinity/ subdirectory is not loaded via DT_NEEDED entries but via explicit dlopen(), which does no path searching at all because the path needed is explicitly specified in the dlopen() call.
(And you need to run /sbin/ldconfig.)
I don't understand the full technical aspects of what you wrote, :-) but what you wrote matches the particular error messages I'm seeing.
Sounds like I was incomprehensible as usual. Job done! :P
Although I asked the question, I was leaning toward /opt/trinity/lib/trinity not being necessary in /etc/ld.so.conf because the equivalent /usr/lib/kde[3] never was needed with KDE3 and everything works as expected.
Stripping away some of my redundant geekberish, the rule is simple enough:
If you link against a shared library via -L/some/dir/here -lfoo, then the dynamic linker is going to be locating your library itself, at process startup (or shared library load), so the directory in which that library is located must exist in /lib/ld.so.conf, and /sbin/ldconfig must be rerun to update /etc/ld.so.cache.
If you load a shared library via dlopen(), you have to give the path to the library there, so there is no need to update ld.so.conf or update ld.so.cache. (Plugins, like the stuff in /usr/lib/kde3 or /opt/trinity/lib/trinity, are invariably opened via dlopen().)
Some extra complexities, rarely important, ludicrously overdesigned, partly undocumented (I should fix that):
- you can override the load path for shared libraries with the LD_LIBRARY_PATH environment variable. This is prepended to the list in ld.so.conf. Don't put a lot in here: it can't be cached and has to be searched on every process startup. Older Unixes with no ld.so cache often grew insanely long paths in their LD_LIBRARY_PATH. These days this is a sign of bad taste.
- there is a 'system list', normally /lib and /usr/lib, which is searched anyway, even if not named in ld.so.conf. If you link with -z nodefaultlib, this is left out.
- there are two ELF tags DT_RPATH and DT_RUNPATH which can also specify colon-separated paths for libraries linked with that executable or shared library. DT_RPATH is strongly deprecated because it is applied *before* LD_LIBRARY_PATH et al, so if it points into a dead network share you will freeze solid whenever you try to start the program. DT_RUNPATH is recommended instead: it is searched later. (In general it is rare to see either used, thank goodness.)
There are a few magic tags that can be used in the paths in DT_RPATH and DT_RUNPATH. $ORIGIN means "." (and is only valid in non-setuid programs for hopefully obvious reasons); $PLATFORM is the platform name (which used to be the value returned by 'uname -p', but since this is almost always 'unknown' these days is now a value derived from the AT_PLATFORM entry in the ELF auxiliary vector supplied by the kernel: something like 'x86_64'); $LIB is the system library directory (/lib, /lib64, something like that).
- the dynamic linker additionally searches a number of other directories under each directory named in ld.so.conf, in response to the hardware capabilities of the system (hence the glibc geek name for this 'hwcaps'). The underlying data for this consists of a 32-bit long passed down from the kernel in the ELF auxiliary vector: running any program with the LD_SHOW_AUXV=t environment variable set will show you this vector. The hwcap string is decoded by code in sysdeps/*/dl-procinfo.[ch] (e.g. sysdeps/i386/dl-procinfo.h): if present, subdirectories named after hwcaps found on the machine are searched before the directories named in ld.so.conf. (The hwcaps are often named the same as the flags in the flags string in /proc/cpuinfo, so you don't need to go through all this rigmarole just to figure out what your machine's hwcaps are). (There is an additional fake hwcap 'tls' which is present only if glibc is capable of thread-local storage, but this is rather irrelevant these days when virtually every system, desktop or not, has TLS support.) (Shared libraries can also add names to the currently-valid list of hwcaps, but I've never seen this feature used. You can mask out hwcaps you don't want the system to pay attention to using the DL_HWCAP_MASK environment variable, but this is really only a debugging aid, or at least I can't imagine another circumstance when you'd want to set it.)
The upshot of all this is that if you have both e.g. MMX and non-MMX-capable versions of a library, you can put the MMX version in a subdirectory of the libdir named 'mmx' and it will be picked up automatically if the hardware is capable of MMX.
This is most commonly used on 32-bit x86 to allow support of 686-class machines that do not support the CMOV instruction (e.g. the Geode LX) by putting CMOV-capable libraries in a cmov/ subdirectory, but it has other uses.
- But that's not all! Any shared libraries named in the LD_PRELOAD environment variable will be loaded before *any* others. This means they can get in first and override symbols in those other libraries, (often deferring to the original symbols later via dlsym (RTLD_NEXT, ...). This is a useful hooking technique for all sorts of obscure purposes: e.g. fakeroot relies on it, as does the Electric Fence malloc debugger.
- But that's not all! Any shared libraries named in /etc/ld.so.preload will be loaded before any others *systemwide*. Using this for anything at all is generally a sign of galloping insanity or being a toolchain or kernel developer (but I repeat myself).
So library loading happens in the order
(initial executable load only) (executable mapped by kernel) /lib/ld-linux.so.2 (or whatever is specified in the DT_INTERP section of the executable: mapped by kernel) /etc/ld.so.preload from LD_PRELOAD (executables and shared libraries below here) from DT_RPATH tag (with all the $ORIGIN/$PLATFORM/$LIB madness) from LD_LIBRARY_PATH from DT_RUNPATH tag (as for DT_RPATH) /etc/ld.so.conf (with all the hwcap searching madness)
If all of these things are in use at the same time, expect to get very, very seriously confused! Thankfully almost all you ever need to pay attention to is /etc/ld.so.conf, and (on proprietary systems) LD_LIBRARY_PATH.
The peculiar thing about this problem is only kword and kpresenter are affected. Possibly there are other "undefined symbol" problems in my builds that I have not yet noticed, but I'm guessing kword and kpresenter are not linking correctly during my builds. I don't know how to debug further or what to look for.
You might find the linker flag --no-undefined (-Wl,--no-undefined in LDFLAGS) to be useful. (I thought Trinity was passing it already, but I could be wrong.)
Other more-or-less-obscure things you might find useful in this hunt:
- dynamic linker symbol debugging, set LD_DEBUG=symbols before running the program: very verbose: see also LD_DEBUG=help (then run any dynamically-linked program at all, e.g. LD_DEBUG=help ls)
- linker symbol tracing, -Wl,--trace-symbol=SYMBOL in LDFLAGS, which prints every file the named symbol appears in