4

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:

  1. 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
    
  2. 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
    
  3. 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;
    
    } 
    
Community
  • 1
  • 1

0 Answers0