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

Re: shared libraries

On Tue, 7 Dec 2004 17:50:01 +0100, martin f krafft <madduck@debian.org> wrote:
> what, rpath? noooooooooo!
> do not hardcode the path.

Could you expand on the scope of this advice?  I'm in the process of
repairing a broken build procedure (for a commercial app that runs on
Debian) and would appreciate the help.

Here's my situation.  The app is written in C++ and includes a server
core and a set of "agent" models.  The models are shared libraries
containing implementations of subclasses of a class "CAgent" whose
interface is known to the server core.  (Each model also contains a
set of routines with C calling conventions that add up to a factory
for instances of one or more subclasses of CAgent.)

So the server core can load these shared libraries with dlopen(), get
the "factory" routines with dlsym(), and obtain implementations of the
CAgent interface via the factory routines.  These implementations in
turn call routines from a set of protocol and utility libraries, some
of which have been built as shared libraries all along and others of
which used to be built statically and compiled into the server core. 
This worked, insofar as the symbols referenced by the models would all
get resolved at dlopen() time, but was less than ideal from the
perspective of catching violations of module boundaries.

I have recently reworked the Makefiles so that the formerly static
libraries are all built as shared objects, linked the models against
them, and verified that all symbols in the models resolve against the
shared libraries.  (Actually, I fixed some recently introduced build
problems in the process; a new file had been added to a static library
used by one of the models but left out of the Makefile, leaving
unresolved symbols in the model, causing mysterious failures to load
the model at run-time.)  Now "ldd -r" runs cleanly on any model -- a
requirement I can start enforcing in the build procedure "smoke tests"
without having to run the server itself.

Now that we have the library dependencies straight, I can start
thinking about refactoring the models and using them from alternate
server cores.  (Some of the models share a lot of code which could be
pulled out as another shared library once we understand their static
structures.)  Another benefit is that I can use ltrace to reverse
engineer the initialization sequence for the shared components (the
sequence is less than obvious from inspection of the server core). 
But there is still a problem with the shared library setup -- the
executable itself and the model shared objects have their RPATH set to
"../lib", requiring the executable to be started from a particular
working directory.

Ideally I'd like to split the install tree for the program into
non-volatile (server binary and shared libraries), semi-volatile
(agents and configurations), and volatile (logs and working data
files).  I'd also like to apply some discipline to the evolution of
the library interfaces, so that we can build additional models
independently and drop them in for use with an existing installation
of the server core.

In a perfect world, I'd give the libraries reasonably unique names and
proper SONAMEs, drop them in /usr/lib, and not need RPATH.  But what
are the disadvantages to an absolute RPATH (not that ../lib kludge) as
long as there are other reasons why the installed path to the binary
has to be determined at build time?

- Michael

Reply to: