В C ++ мне нужно запустить несколько экземпляров устаревших библиотек FORTRAN (над которыми я не имею никакого контроля), которые используют переменные COMMON BLOCK. Я могу успешно сделать это по рецепту Вопрос 3433522, где я создаю 2 физические копии библиотеки и загружаю их во время выполнения, используя dlopen
(см. пример кода ниже).
Однако я хотел бы избежать создания двух физических копий библиотеки, поскольку она может быть довольно большой. Как предложено в Вопрос 3433522, с помощью RTLD_PRIVATE
будет работать, но это не доступно (насколько я могу судить) в libgc
с GCC. Я также исследовал с помощью RTLD_DEEPBIND
скорее, чем RTLD_LOCAL
но это не имеет значения. Любая идея, как это может быть достигнуто с помощью GCC?
Мой пример кода выглядит следующим образом:
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;
}
Задача ещё не решена.