Domanda

Introduzione

mi scuso in anticipo per la lunga domanda. E 'il più breve ho potuto farlo, che è, purtroppo, non è molto breve.

Configurazione

Ho definito due interfacce, A e B:

class A // An interface
{
public:
  virtual ~A() {}

  virtual void whatever_A()=0;
};

class B // Another interface
{
public:
  virtual ~B() {}

  virtual void whatever_B()=0;
};

Poi, ho una libreria condivisa "TestC" costruire oggetti della classe C, implementazione sia A che B, e poi svenire puntatori a loro A-Interfaccia:

class C: public A, public B
{
public:
  C();
  ~C();

  virtual void whatever_A();
  virtual void whatever_B();
};

A* create()
{
  return new C();
}

Infine, ho una seconda una libreria condivisa "testd", che prende un A* come input, e cerca di lanciarlo ad un B*, utilizzando dynamic_cast

void process(A* a)
{
  B* b = dynamic_cast<B*>(a);
  if(b)
    b->whatever_B();
  else
    printf("Failed!\n");
}

Infine, ho ricorso principale, passando A* di tra le librerie:

A* a = create();
process(a);

Domanda

Se io costruisco la mia domanda principale, che collega contro la 'TestC' e biblioteche testd ', tutto funziona come previsto. Se, tuttavia, modifico l'applicazione principale di non linkare 'TestC' e 'testd', ma invece caricarli in fase di esecuzione utilizzando dlopen / dlsym, poi il dynamic_cast fallisce.

Non capisco perché. Eventuali indizi?

Ulteriori informazioni

È stato utile?

Soluzione

ho trovato la risposta alla mia domanda qui . A quanto ho capito, ho bisogno di fare il typeinfo disponibile in 'TestC' a disposizione del 'testd' biblioteca. Per fare questo quando si utilizza dlopen(), due cose in più devono essere fatte:

  • Quando si collega la biblioteca, passare il linker l'opzione -E, per assicurarsi che esporta tutti i simboli all'eseguibile, non solo quelli che sono irrisolti in esso (perché ci sono nessuno)
  • Quando si carica biblioteca dlopen(), aggiungere l'opzione RTLD_GLOBAL, per assicurarsi che i simboli esportati da testc sono disponibili anche per testd

Altri suggerimenti

In generale, gcc non supporta RTTI attraverso i confini dlopen. Ho esperienza personale con questo rovinare try / catch, ma il problema sembra che più dello stesso. Purtroppo, temo che è necessario attenersi alle cose semplici attraverso dlopen.

Devo aggiungere a questa domanda da quando ho incontrato questo problema pure.

Anche quando fornisce -Wl,-E e utilizzando RTLD_GLOBAL, i dynamic_casts ancora non è riuscito. Tuttavia, passando -Wl,-E in linkage dell'applicazione reale così e non solo nella libreria sembrano aver riparato.

Se uno non hanno alcun controllo sulla fonte del ricorso principale, -Wl, -E non è applicabile. Passando -Wl, -E al linker, mentre la costruzione propri binari (il padrone di casa così e i plugin) non aiuta neanche. Nel mio caso l'unica soluzione di lavoro era per caricare e scaricare il mio ospite così dalla funzione _init dell'ospite modo stesso utilizzando RTLD_GLOBAL bandiera (Vedi codice qui sotto). Questa soluzione funziona in entrambi i casi:

  1. i principali collegamenti di applicazioni contro l'host in modo.
  2. le principali carichi di applicazioni ospita in modo da utilizzare dlopen (senza RTLD_GLOBAL).

In entrambi i casi si deve seguire le istruzioni indicate da gcc wiki visibilità .

Se si fa simboli del plugin e l'host in modo visibile tra loro (utilizzando #pragma GCC visibilità push / pop o attributo corrispondente) e carica i plugin (dall'host così) utilizzando RTLD_GLOBAL 1. funzionerà anche senza carico e scarico proprio modo (come detto da collegamento sopra riportato). Questa soluzione rende 2. lavorano anche che non è stato il caso prima.


// get the path to the module itself
static std::string get_module_path() {
    Dl_info info;
    int res = dladdr( (void*)&get_module_path, &info);
    assert(res != 0); //failure...

    std::string module_path(info.dli_fname);
    assert(!module_path.empty()); // no name? should not happen!
    return module_path;
}

void __attribute__ ((constructor)) init_module() {
    std::string module = get_module_path();

    // here the magic happens :)
    // without this 2. fails
    dlclose(dlopen(module.c_str(), RTLD_LAZY | RTLD_GLOBAL));
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top