This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  Path To EXE For DSOs
  Submitted by



I just read the "path to executable" article in the code of the day, and I thought I'd explain how I solved a similar problem with dynamic libraries.

The "path to executable" is important because it lets you build software distributions that are relocatable in the file system: you can move it around and it keeps working because supporting files can be found relative to the binary.

A similar problem occurs when the binary is not monolithic, but needs several private dynamic libraries before it loads (not plugins, which are loaded after the binary is running, and can be located using the path-to-exe method, but DLL/DSO's that are actually needed by the app to simply load).

This problem also has a solution, different for each platforms.

On Win32:
On Win32, the problem isn't a problem: by default Win32 searches for needed DLL's in the directory where the binary was found: the equivalent of having a permanent ${EXE_DIR} prepended to LD_LIBRARY_PATH on Unix.

On Linux (and I guess other ELF-based systems)
On Linux, the problem is annoying and many software distributions end up solving the problem in one of three ways:

1. Install your DSO's in a standard place. This solution albeit a standard Unix practice is IMHO a lousy one: the filesystem pollution that ensues is horrible, everything piles up in the same place and un-installing an app. is a nightmare. And of course, you software can't be relocated.

2. Install your software in your own private directory, and add the path to the DSO's in LD_LIBRARY_PATH. This solution works slightly better than 1., but is still a lousy one. If Linux is ever going to become a mainstream OS, you can't expect non-technical users to go and fiddle with that kind of stuff.

3. The shell wrapper solution, where you basically launch a shell script instead of your app. The shell figures out where it is in the file system, sets the various PATH's and finally launches the real program. This works, but it is more convoluted than necessary, especially if you software is made of lots of small binaries: you'd need a wrapper shell for each.

After struggling with the issue, I contacted Ulrich Drepper at redhat (the guy that maintains glibc), and after a little grumbling about people who don't read the ELF specs at breakfast, he gave me a very neat solution. There is an apparently little-known paragraph in the ELF specification manual about path substitutions: it lets you build a DSO whose soname contains variables that will be interpreted at load time.

One of these variables is $ORIGIN: it contains at load time the "path to the calling module". Practically: the path to the binary that needs the dynamic library.

So, in other words, you can get the Linux dynamic loader to actually implement the Win32 behaviour. Here's how it's done in practice (the example here is with C++ code):


	# Build DSO needed.so
	g++
		-shared
		-Wl,-soname
		-Wl,'${ORIGIN}/needed.so'	# Make sure to double the $ sign
		-o needed.so			# if you call this from a Makefile
		obj1.o
		obj2.o
		obj3.o

# Build application binary.exe g++ -o tst.exe tstMain.o needed.so



And voilą! : you have two files tst.exe and needed.so that can be freely moved about in the file system, and as long as they are in the same directoy, tst.exe will work like a charm.

On OSX:
OSX is not an ELF based system (ther binary format is called Mach-O), so the Linux solution won't work, but the problem exists nonetheless.

First, on OSX, there is a rather stern distinction between two types of dynamically loadable objects: Dynamic libraries and bundles (not to be confused with OSX "filesystem bundles" that are just directories that are somehow tagged and treated as a single file by the finder).

These two type of loadable objects are built and loaded differently. Bundles are designed to be "plug-ins", and loaded via a dlopen-like call. They can't be linked against and are thus irrelevant to this discussion.

OTOH, the dynamic libraries (.dylib) are designed to be linked against (although you can also do a dlopen-like thing on them later, but that is not recommended by design) suffer from the exact same problem: when the binary loads, it needs to locate them, and it is done via one of the three methods very much like those described in the Linux case.

But, never fear, just as in the ELF case, there is a way to tell the dynamic linker to look for dylibs in a path relative to your binary. Here's how it's done:


	export MACOSX_DEPLOYMENT_TARGET=10.2
	g++
		-dynamic
		-prebind
		-dynamiclib
		-flat_namespace
		-Wl,-single_module
		-install_name @executable_path/needed.dylib
		obj1.o
		obj2.o
		obj3.o



That's it for today.

Enjoy,


- Mgix

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.