In C++ I need to run multiple instances of legacy FORTRAN libraries (over which I have no control) which use COMMON BLOCK variables. I can successfully do this following the prescription of Question 3433522, where I create 2 physical copies of the library, and load these at run-time using dlopen
(see example code below).
However, I would like avoid having to create two physical copies of the library, as it can be rather large. As suggested in Question 3433522, using RTLD_PRIVATE
would work, but this is not available (as far as I can tell) in libgc
with GCC. I've also investigated using RTLD_DEEPBIND
rather than RTLD_LOCAL
but this makes no difference. Any idea how this could be accomplished using GCC?
My example code is as follows:
Makefile
libgen.so: gen.f gfortran -Wall -shared -fPIC -o $@ $< libgen%.so: libgen.so cp $< $@ run: run.cpp libgen1.so libgen2.so g++ -Wall -o $@ $< -L. -ldl
gen.f
C********************************************************************* C...GENDATA C...Common block of data. BLOCK DATA INTEGER NEVENT COMMON/GENDATA/NEVENT DATA NEVENT/0/ END C********************************************************************* C...EVENT C...Simple example routine that produces an "event". SUBROUTINE GENERATE() INTEGER NEVENT COMMON/GENDATA/NEVENT NEVENT = NEVENT + 1 PRINT *, NEVENT RETURN END
run.cpp
#include <iostream> #include <dlfcn.h> using namespace std; //========================================================================== // Methods to load and close dynamic libraries. //-------------------------------------------------------------------------- // Load a symbol from a library. typedef void (*Symbol)(); Symbol libSym(void *&lib, string libName, string symName) { Symbol sym(0); const char* error(0); // Load the library, if not loaded. if (!lib) { lib = dlopen(libName.c_str(), RTLD_NOW | RTLD_LOCAL); error = dlerror(); } if (error) { cerr << "Error from libSym: " + string(error) + "\n"; return sym; } dlerror(); // Load the symbol. sym = (Symbol)dlsym(lib, symName.c_str()); error = dlerror(); if (error) cerr << "Error from libSym: " + string(error) + "\n"; dlerror(); return sym; } //-------------------------------------------------------------------------- // Close a library. void libClose(void *&lib) { if (lib) {dlclose(lib); dlerror();} } //========================================================================== // The main program. //-------------------------------------------------------------------------- int main() { // Load libraries. void *libgen1(0), *libgen2(0); cout << "Loading library 1.\n"; void (*generate1)(); generate1 = libSym(libgen1, "./libgen1.so", "generate_"); if (!libgen1) return 1; cout << "Loading library 2.\n"; void (*generate2)(); generate2 = libSym(libgen2, "./libgen2.so", "generate_"); if (!libgen2) return 1; // Generate events. cout << "Generating 1.\n"; (*generate1)(); cout << "Generating 1.\n"; (*generate1)(); cout << "Generating 2.\n"; (*generate2)(); // Close the libraries. libClose(libgen1); libClose(libgen2); return 0; }