Статические и динамические связи конфликты и дублирование


У меня есть код, статически линкуется один вариант альтернативы. Теперь идет библиотека B, которая используется A через dlopen (). B также зависит от mpich, но динамически связан с ним.

Проблема заключается в том, что теперь для того, чтобы B воспользовался распределением mpi, необходимо получить доступ к коммуникатору, который в настоящее время обрабатывается A. этот коммуникатор был создан статической версией mpich, когда B вызывает подпрограммы MPI, он будет использовать динамическую версию MPI, которая не является статической версией mpich. guarateed должен быть совместим со статической версией, присоединенной к A.

Такова общая картина. Я думаю, что единственное решение состоит в том, чтобы mpich динамически связывался как для A, так и для B. Однако я не совсем понимаю следующее:

  • как работает линкер обработки общих зависимостей объектов проявлявшаяся при вызове динамическом связывании? Будет ли у меня два экземпляра mpich в VM также с динамической компоновкой, или компоновщик достаточно умен, чтобы понять, что символы, необходимые для dlopened B, являются уже в адресном пространстве и рассосется против тех.
  • можно ли сказать компоновщику: когда вы открываете эту библиотеку, не берите динамическую зависимость, а разрешите ее с помощью статических символов, которые уже предоставлены
2 2

2 ответа:

Вы не сказали, Какой набор инструментов (GCC, LLVM, MSC и т. д.) вы используете, наиболее полезный ответ будет зависеть от этой информации.

Могу я предложить вам посмотреть на "рамки исключений GCC" http://www.airs.com/blog/archives/166 .

Если это полезно, то Gold Linker, который доступен для GCC и LLVM, поддерживает оптимизацию времени соединения и может работать в режиме "Make" с DLLTool http://sourceware.org/binutils/docs/binutils/dlltool.html .

Действительно так возможно, чтобы статический и динамический код вызывали друг друга, компьютер не заботится; он будет "запускать" все, что ему подают-будет ли это работать именно так, как вы хотите, или HCFs зависит от правильного кода и правильных команд компоновщика.

Использование отладчика не будет весело. Было бы лучше исказить имена перед связыванием, чтобы при отладке вы могли видеть, из какого модуля пришел код. После того, как он будет запущен и запущен, вы можете отменить Mangle и иметь одноименные функции Link (чтобы убедиться, что он все еще функционирует).

Ошибки компилятора / компоновщика не будут вашим другом.

Такой сценарий (статическое и динамическое связывание) чаще встречается в MinGW и Cygwin, где некоторые библиотеки статичны, но библиотека, которую вы загружаете из интернета, доступна только в динамической форме (без источника).

Если библиотека состоит из двух различных цепей инструментов компилятора, то возникают другие проблемы, см. Этот поток StackOverflow: "linking dilemma (undefined ссылка) между MinGW и MSVC. MinGW терпит неудачу MSVC works ".

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

Вы даже можете загрузить динамическую библиотеку и вызвать ее (статически), а затем повторно загрузить ее части позже.

Как сильно вы привязаны к памяти и как быстро вы хотите Функции для запуска, если все находится в памяти, ваша программа может сразу же передать выполнение вызываемым функциям, если вы меняете часть своего кода на виртуальную машину, время выполнения действительно будет поражено.

Запуск профилировщика в коде поможет решить, какие части библиотеки следует загрузить, если вы хотите выполнить "динамическое динамическое связывание" (полный контроль над динамическим связыванием путем загрузки динамической библиотеки, чтобы ее можно было использовать статически). Вот что такое головные боли и кошмары. сделан из него. ГЛОССАРИЙ.

Короче говоря: это зависит от вариантов dlopen. По умолчанию, если символ, необходимый запрашиваемой библиотеке, уже существует в глобальной области, он будет использован повторно (это то, что вы хотите). Но вы можете обойти это поведение с помощью RTLD_DEEPBIND, с этим флагом зависимости не будут повторно использоваться из глобальной области и будут загружены во второй раз.

Вот некоторый код, чтобы воспроизвести вашу ситуацию и продемонстрировать эффект этого флага.

Давайте создадим общую библиотеку, которая будет использоваться обеими lib A и программа эта библиотека будет существовать в двух версиях.

$ cat libcommon_v1.c 
int common_func(int a)
{
    return a+1;
}
$ cat libcommon_v2.c 
int common_func(int a)
{
    return a+2;
}

Теперь давайте напишем lib A, который использует libcommon_v2:

$ cat liba.c 
int common_func(int a);

int a_func(int a)
{
    return common_func(a)+1;
}

И, наконец, программа B, которая динамически связывается с libcommon_v1 и dlopens lib A:

$ cat progb.c
#include <stdio.h>
#include <dlfcn.h>

int common_func(int a);
int a_func(int a);

int main(int argc, char *argv[])
{
    void *dl_handle;
    int (*a_ptr)(int);
    char c;

    /* just make sure common_func is registered in our global scope */
    common_func(42);

    printf("press 1 for global scope lookup, 2 for deep bind\n");
    c = getchar();
    if(c == '1')
    {
        dl_handle = dlopen("./liba.so", RTLD_NOW);
    }
    else if(c == '2')
    {
        dl_handle = dlopen("./liba.so", RTLD_NOW | RTLD_DEEPBIND);
    }
    else
    {
        printf("wrong choice\n");
        return 1;
    }
    if( ! dl_handle)
    {
        printf("dlopen failed: %s\n", dlerror());
        return 2;
    }
    a_ptr = dlsym(dl_handle, "a_func");
    if( ! a_ptr)
    {
        printf("dlsym failed: %s\n", dlerror());
        return 3;
    }

    printf("calling a_func(42): %d\n", (*a_ptr)(42));

    return 0;
}

Давайте построим и запустим все вещи:

$ export LD_LIBRARY_PATH=.
$ gcc -o libcommon_v1.so -fPIC -shared libcommon_v1.c
$ gcc -o libcommon_v2.so -fPIC -shared libcommon_v2.c
$ gcc -Wall -g -o progb progb.c -L. -lcommon_v1 -ldl
$ gcc -o liba.so -fPIC -shared liba.c -L. -lcommon_v2
$ ./progb 
press 1 for global scope lookup, 2 for deep bind
1
calling a_func(42): 44
$ ./progb 
press 1 for global scope lookup, 2 for deep bind
2
calling a_func(42): 45

Мы можем ясно видеть, что с опциями по умолчанию dlopen повторно использует символ common_func, который присутствовал в программе B, и что с RTLD_DEEPBIND libcommon был загружен снова, и библиотека A получила свою собственную версию common_func.