0

I am currently looking for ways to expose the location of a shared library on Linux such that it can be picked up easily by any program installed separately. I want to make this location configurable so it can point to different possible installations of the same library. Examples of similar cases I can think of would be Qt5 and Java.

To make a long story short, I am developing FreeRDS, a FreeRDP-based Remote Desktop Services stack. Server-side RDS-aware applications link to libwinpr-wtsapi, a stub library that exposes the Microsoft Windows Terminal Services API interface, but does not implement it. This enables applications to link to libwinpr-wtsapi without having to link directly to a specific RDS implementation. On the first call to any of the WTSAPI functions, the real implementation is loaded dynamically by libwinpr-wtsapi. However, the location of the dynamic library implementing the WTSAPI (here, FreeRDS) needs to be known.

Right now, I am achieving this by setting an environment variable with the full path to the library:

export WTSAPI_LIBRARY=/opt/freerds/lib/x86_64-linux-gnu/libfreerds-fdsapi.so

However, this is not very practical, as this environment variable would need to be set for every program using the WTSAPI. In this case, I have my installation of FreeRDS in /opt/freerds.

I am thinking I could probably simplify this by using a single environment variable to expose the installation prefix of FreeRDS on the system, with something similar to JAVA_HOME:

export FREERDS_HOME=/opt/freerds

However, I then need to know the proper library subdirectory. It is also important to know that it would be possible in the future to offer both a 32-bit and a 64-bit version of the library offering the FreeRDS WTSAPI. This library basically performs RPC with the FreeRDS session manager, so that would be definitely possible.

Let's say we have FREERDS_HOME properly set, or that FreeRDS is installed in the default installation prefix of the system, which files would be "standard" to offer some additional installation configuration information? Here I'm thinking I could have an equivalent of Qt5's qt.conf that would specific installation subdirectories, like the 64-bit installation subdir, the 32-bit installation subdir, etc. However, I don't know where I should be putting that file. Should it be in <prefix>/etc/freerds/freerds.conf?

Ideas, anyone? Thank you!

brokenfoot
  • 11,083
  • 10
  • 59
  • 80
awakecoding
  • 428
  • 5
  • 15
  • Package it for your favorite distribution; install it in `/usr/lib/libfreerds-fdsapi.so` or something near. – Basile Starynkevitch Mar 17 '14 at 16:39
  • "*... to make this location configurable so it can point to different possible installations of the same library.*": "*different*" in terms of what? Release-version, platform, features? – alk Mar 17 '14 at 16:46
  • System wide library paths are configured in /etc/ld.so.conf , is that what you need ? – nos Mar 17 '14 at 17:01
  • You could always set up function pointers via `dlopen()` and `dlsym()`, rather than directly linking the library against your target. This would require some extra coding on your part, but makes it dead easy to support multiple version of your library in a clean, easy-to-read manner. – Cloud Mar 17 '14 at 17:05
  • The WTSAPI implementation (libfreerds-fdsapi.so) is already a library meant to be loaded dynamically by libwinpr-wtsapi.so. libfreerds-fdsapi.so exports a single entry point that returns a pointer to an array of callbacks. libwinpr-wtsapi.so exports functions with the same signatures, and calls the dynamically-loaded callbacks. This allows programs to link to libwinpr-wtsapi.so without being linked directly to a specific WTSAPI implementation. – awakecoding Mar 17 '14 at 21:27
  • @BasileStarynkevitch installing the library globally on the system defeats the purpose of my question which is making the location of the libraries configurable so it could point to custom installation prefixes. For instance, there could be a "vanilla" installation in /usr, and a vendor-provided installation in /opt/vendor. Just think of how multiple versions of Java or Qt5 can coexist on a system, there will be many cases where we cannot assume that there is always a single FreeRDS installation which is installed in a global prefix. – awakecoding Mar 17 '14 at 21:34

4 Answers4

0

some (many? all?) Linux distributions today include environment-modules, which aim is exactly to make available many different versions of the same software by customizing the environment (and eventually, shell aliases/functions) with easy front-end commands.

You can find all the needed information here.

Sigi
  • 4,826
  • 1
  • 19
  • 23
  • I didn't know about environment-modules, but I don't think this would be appropriate for my case. Correct me if I'm wrong, but looking at the "Quick Examples" it looks like one needs to manually switch modules for the changes to take effect. Let's say I have a vanilla installation of FreeRDS in /usr and a vendor-specific installation in /opt/vendor. I want to expose either /usr or /opt/vendor as my FREERDS_HOME globally on the system, and be able to configure that path. A configuration file in a global path like /etc/freerds/freerds.conf could do it, but I'm not sure if it's "standard". – awakecoding Mar 17 '14 at 21:55
  • with modules you just give the ability to the user to 1. have an immediate view of which version are available (`module list`) and 2. select one among them (`module load` or `module switch`). It works by just setting FREERDS_HOME. For the "standard" place, I'd think `/etc/freerds` is the place for the system-wide installation, the one under /usr. I would expect to find the configuration file for the one in /opt/vendor in /opt/vendor/etc. I'm not sure they should refer the same config file: what if different versions support different configuration options? – Sigi Mar 18 '14 at 08:19
0

Thanks for the multiple answers, here is the solution I finally opted for that satisfies my needs:

As explained earlier, there could be more than one installation of FreeRDS on the same system, but only one of them running at once. We can also assume FreeRDS is supposed to be running before we can attempt to interact with it. Knowing this, I modified FreeRDS to write a simple configuration file in /var/run/freerds.instance with the install prefix and installation subdirectories. This is very similar to having a .pid file, except we're exposing installation paths.

The freerds.instance file is using the .ini format, which is fairly common in configuration files. All that libwinpr-wtsapi has to do is parse /var/run/freerds.instance to find the installation prefix of the current FreeRDS instance, along with the library subdir, so we can find the correct libfreerds-fdsapi.so.

Here is what a sample freerds.instance file looks like:

[FreeRDS]
prefix="/opt/freerds"
bindir="bin"
sbindir="sbin"
libdir="lib/x86_64-linux-gnu"
datarootdir="share"
localstatedir="var"
sysconfdir="etc"

I prefer this solution because it requires literally no special configuration, setting of environment variables, etc. No matter what, we always find the proper FreeRDS installation wherever it is on the system.

awakecoding
  • 428
  • 5
  • 15
0

You can add a $ORIGIN rpath to your executable, that makes it load libraries relative to the directory the executable is in. (See "ld: Using -rpath,$ORIGIN inside a shared library (recursive)"). This probably applies to dlopen() too.?

$ gcc ... -Wl,-rpath,'$ORIGIN/../lib/dir' -lsomething 

I've also found you can run the dynamic linker directly to get some debug facility:

$ /lib/ld-linux.so.2
Usage: ld.so [OPTION]... EXECUTABLE-FILE [ARGS-FOR-PROGRAM...]
...
   --list                list all dependencies and how they are resolved
Community
  • 1
  • 1
David Leonard
  • 1,694
  • 1
  • 17
  • 14
  • I am already using relative RPATHs for my binaries. What we are talking about here is dynamically loading a library for which we do not previously know the location, which is a different thing. – awakecoding Mar 25 '14 at 18:55
-1

export LD_LIBRARY_PATH=/yourso.so

Vinod Patidar
  • 372
  • 1
  • 4
  • 12