views:

1046

answers:

3

Hi all,
I have an application a part of which uses shared libraries. These libraries are linked at compile time.
At Runtime the loader expects the shared object to be in the LD_LIBRARY_PATH , if not found the entire application crashes with error "unable to load shared libraries".Note that there is no guarantee that client would be having the library, in that case I want the application to leave a suitable error message also the independent part should work correctly.
For this purpose I am using dlsym() and dlopen() to use the API in the shared library. The problem with this is if I have a lot of functions in the API, i have to access them Individually using dlsym and ptrs which in my case are leading to memory corruption and code crashes.
Are there any alternatives for this.

Thanx.

+1  A: 

You can wrap your application with another one which first checks for all the required libraries, and if something is missing it errors out nicely, but if everything is allright it execs the real application.

florin
It is quite common for an application to have a script that set up the LD_LIBRARY_PATH before starting the application.
Martin York
The problem is not that.. the problem is if the library is not present with client that module shouldn't work, the rest of the code should work correctly.. but in this case if the library is not found the code fails to execute.
Neeraj
A: 

Your problem is that the resolution of unresolved symbols is done very early on - on Linux I believe the data symbols are resolved at process startup, and the function symbols are done lazily. Therefore depending on what symbols you have unresolved, and on what sort of static initialization you have going on - you may not get a chance to get in with your code.

My suggestion would be to have a wrapper application that traps the return code/error string "unable to load shared libraries", and then converts this into something more meaningful. If this is generic, it will not need to be updated every time you add a new shared library.

Alternatively you could have your wrapper script run ldd and then parse the output, ldd will report all libraries that are not found for your particular application.

Beano
+8  A: 

The common solution to your problem is to declare a table of function pointers, to do a single dlsym() to find it, and then call all the other functions through a pointer to that table. Example (untested):

// libfoo.h
struct APIs {
   void  (*api1)(void);
   void *(*api2)(int);
   long  (*api3)(int, void *);
};

// libfoo.cc
void fn1(void) { ... }
void *fn2(int) { ... }
long fn3(int, void *) { ... }

APIs api_table = { fn1, fn2, fn3 };


// client.cc
#include "libfoo.h"
...
  void *foo_handle = dlopen("libfoo.so", RTLD_LAZY);
  if (!foo_handle) {
     return false;            // library not present
  }
  APIs *table = dlsym(foo_handle, "api_table");
  table->api1();              // calls fn1
  void *p = table->api2(42);  // calls fn2
  long x = table->api3(1, p); // calls fn3

P.S. Accessing your API functions individually using dlsym and pointers does not in itself lead to memory corruption and crashes. Most likely you just have bugs.

EDIT:
You can use this exact same technique with a 3rd-party library. Create a libdrmaa_wrapper.so and put the api_table into it. Link the wrapper directly against libdrmaa.so.

In the main executable, dlopen("libdrmaa_wrapper.so", RTLD_NOW). This dlopen will succeed if (and only if) libdrmaa.so is present at runtime and provides all API functions you used in the api_table. If it does succeed, a single dlsym call will give you access to the entire API.

Employed Russian
and how do I call dlopen() to get the foo_handle? I mean will it load the API shared object say libAPI.so automatically??
Neeraj
It is dlopen() actually for opening the library... :).. nyways I got ur point.. but this works only if there is a APIs structure in the library.. which u can't expect with a 3rd party library..I am trying to use sungrid api libdrmaa.so..
Neeraj
Instead of getting a pointer to a table, you could instead get a pointer to a function which when called returns the pointer to the table. This allows the plugin to initialize itself before any other function is called, and even create the table dynamically.
CesarB