Как динамически загружать и вызывать символ, который имеет специфичный для библиотеки тип в качестве параметра функции - PullRequest
2 голосов
/ 27 сентября 2019

Предположим, у меня есть следующее:

// lib1.h
struct S 
{
    int x;
};
void f(S* s);  // defined in .cpp

и

// lib2.h
struct S 
{
    int x;
    int y;
};
void f(S* s);  // defined in .cpp

В результате lib1.so и lib2.so.

Итак, мой вопрос:

#include <dlfcn.h>

int main()
{
    const auto lib_to_use = <some application level logic, resulting in lib1.so or lib2.so>;
    const auto lib = dlopen(lib_to_use, RTLD_LAZY);
    assert(lib);

    const auto func = dlsym(lib, "f");
    assert(func);

    // how do I call `func`, given the fact it takes different, library-specific type `S`?

    dlclose(lib);
}

Моя реальная проблема - как мне загрузить во время выполнения libfuse2 или libfuse3 и выполнить fuse_main_real, учитывая тот факт, что этоимеет параметр fuse_operations*, то есть struct с указателями на функции, но с разными типами для двух версий?

Edit : я не верю, что это нарушает одно определениеправило - только один из них будет связан одновременно, но никогда не оба.(Я также не уверен, что ODR не работает, если оба загружены, так как они используются вручную, но это другая тема)

Ответы [ 2 ]

1 голос
/ 28 сентября 2019

как мне позвонить func, учитывая тот факт, что он принимает другой, специфичный для библиотеки тип S?

Очевидно, вы не можете иметь тип S в своемОсновная программа, которая соответствует одновременно lib1 S и lib2 S.Таким образом, вы должны объявить два отдельных типа: S1 и S2.

Остальное тривиально:

int version = which_version_should_I_use();
if (version == V1) {
  void *h = dlopen("lib1.so", RTLD_LAZY);
  void (*fn)(S1*) = (void (*)(S1*))dlsym(h, "f");
  assert(fn != NULL);
  S1 s = ...;
  fn(&s);
} else {
  // must be V2
  void *h = dlopen("lib2.so", RTLD_LAZY);
  void (*fn)(S2*) = (void (*)(S2*))dlsym(h, "f");
  assert(fn != NULL);
  S2 s = ...;
  fn(&s);
}
0 голосов
/ 27 сентября 2019

В той мере, в какой стандарт можно сказать, что он применяется к динамическим объектам, вы правы, что не существует нарушения ODR между несколькими объектами, которые никогда не загружаются вместе (потому что нет программы , которая содержит обаопределения).То же самое нельзя сказать о вашей программе, если она содержит определение каждого типа класса (очевидно) или содержит определение одного и (выбор времени выполнения таков) загружает динамический объект, который использует другой.(С библиотеками DLL ситуация более странная: типы являются общими, но не их функциями-членами, статическими членами данных или символами RTTI.)

Ответ заключается в том, чтобы эти определения были разделены: Обтекание каждое динамическоеобъект в одном из ваших собственных объектов (связанный с ним простым -l), который предоставляет общий интерфейс (что должно быть возможно, чтобы вопрос имел смысл).Загрузите один или другой из этих в основную программу и вызовите его, используя уникальный тип (ы) #include d из этого интерфейса.

...