[Osi] [Patch] loading gurobi library at runtime

Christophe-Marie Duquesne chm.duquesne at gmail.com
Fri Nov 5 11:59:47 EDT 2010


Hi,

Right now, packaging OSI is hard, especially for the following reason:
if you want OSI to support the solver XXX, you need to link it to the
library of the solver XXX. An OSI could be compiled with support for
every solvers, but this would require the user to have every solvers
on his machine, otherwise when using OSI in his own code, linking to
OSI libs would result in missing symbols, so it practically not
feasible.

This can be fixed in a very un-intrusive way: the principle is to
write code that defines the missing functions and properly loads their
symbols at runtime if the library is found in the standard system
library path. This can even be done in a portable way, using libltd,
that comes with the autotools. I successfully applied this approach to
gurobi. Here is how I do that:
---
I originally have:
---
--
file OsiXXXSolverInterface.cpp:
--
#include <XXX.h>
// use of int XXXfoo()
// use of void XXXbar(int)

---
How I fix it:
---
I write XXX_symbols.h and XXX_symbols.c that define XXXfoo and XXXbar
(the symbols that would be missing), and offers routines to load them
at runtime.
--
file XXX_symbols.h:
--
// handle to the symbols
void * _XXXhandle;

// routines to load/unload the symbols
int loadXXXsymbols();
int unloadXXXsymbols();

// to avoid symbol name collisions with libXXX internals, I use
#define statements
#define XXXfoo _libXXX_XXXfoo
#define XXXbar _libXXX_XXXbar

// function pointers that will be set at load
int (*_libXXX_XXXfoo)();
void (_libXXX_XXXbar)(int);

--
file XXX_symbols.c
--
int loadXXXsymbols() {
  lt_dlinit();

  // try to load libXXX and its dependency (missing libraries can be
handled from there)
  lt_dlopen("libXXX_dependency1");
  lt_dlopen("libXXX_dependency2");
  _XXXhandle = lt_dlopen("libXXX");

  // define the symbols
  _libXXX_XXXfoo = lt_dlsym(XXXhandle, "XXXfoo");
  _libXXX_XXXbar = lt_dlsym(XXXhandle, "XXXbar");
  return 0;
}

int unloadXXXsymbols() {
  lt_dlclose(XXXhandle);
  lt_dlexit();
  return 0;
}

Then I modify OsiXXXinterface.cpp and change only two things:
- I remove the header XXX.h and replace it with XXX_symbols.h.
- I call loadXXXsymbols() in the constructors, unloadXXXsymbols() in
the destructor. (libltdl actually unload symbols when lt_dlcose has
been called the same number of times as lt_dlopen.)

Why do I say it is not intrusive: In terms of modifications of the
existing code, you just write XXXsymbols.c, XXXsymbols.h (additional
files). The modifications on the existing code just occur in the
constructor/destructor of OsiXXXSolverInterface, and in the include.
This minimizes the impact of the patch and probably prevents bugs to
be introduced. This method just works fine for gurobi, and I intend to
apply it to other solvers. Attached is a patch that does what I
described. I tested it and ran the testsuite to the point my version
and the trunk version they both crashed in the same test ( ;) ). I
also successfully ran it on examples from a private project and it
worked as good as the original OsiGrbSolverInterface.

One last thing: In order to get my patch to compile, I horribly hacked
the buildsystem, so what I'm attaching in terms of buildsystem is what
was just enough for me to get the autotools stuff to work. You
probably want to modify that by yourself (especially coin.m4).

Cheers,
Christophe-Marie Duquesne
-------------- next part --------------
A non-text attachment was scrubbed...
Name: osi-gurobi-runtime-load.patch
Type: text/x-patch
Size: 39154 bytes
Desc: not available
URL: <http://list.coin-or.org/pipermail/osi/attachments/20101105/5d9a5899/attachment.bin>


More information about the Osi mailing list