Как разделить глобальную переменную между основным процессом и динамической библиотекой c через библиотеку stati c (macOS)? - PullRequest
2 голосов
/ 24 января 2020

Мой вопрос, похоже, похож на этот вопрос, однако в моем случае общая переменная находится в stati c библиотеке, а также советы из этого вопроса мне не помогли: Обмен глобальными данными между общей библиотекой и основной . По пути я видел проблемы из этого вопроса, но также не нашел окончательного решения: компоновщик OS X не смог найти символы из файла C, который содержит только переменные .

Я пытаюсь создайте мой основной процесс и динамическую c библиотеку, чтобы она dlopen разделяла глобальную переменную SHARED, расположенную в общей библиотеке, на которую они оба ссылаются.

Я создал минимальный проект на GitHub , но я также предоставляю содержание этого проекта ниже.

Проблема: Вывод, который я ожидаю, состоит в том, чтобы увидеть одну и ту же переменную и один и тот же адрес в обоих случаях. Вместо этого я вижу две копии переменной SHARED.

Мой вопрос: какая комбинация флагов компиляции и компоновщика могла бы удалить второй экземпляр переменной SHARED, чтобы только один экземпляр был должным образом распределен между основным процессом и динамикой c library.

Дополнительный фон

После дополнительных исследований, я думаю, этот вопрос можно свести к следующему: как получить поведение Linux -rdynamic flag?

Я не собираюсь запускать подобный код. Я портирую существующее программное обеспечение, которое работает на Linux. Это программное обеспечение разделяет глобальные переменные между его основным процессом и динамическими библиотеками c. Я убедился, что он использует -rdynamic для достижения такого поведения на Linux: на Linux, просто добавив -rdynamic к флагам компоновщика исполняемого файла моего примера! сделать глобальную переменную доступной для общего доступа.

Что именно делает -rdynamic и когда именно это необходимо? описывает поведение, которое я ищу:

Если вы используете «dlopen» для загрузки динамического c объекта, который должен ссылаться на символы, определенные программой, а не на какой-либо другой динамический c объект, то вам, вероятно, понадобится использовать эту опцию при компоновке Сама программа. ...

Теперь проблема в том, что я не могу добиться такого поведения с моим примером на macOS. Добавление -rdynamic, кажется, не имеет эффекта, который он имеет на Linux.

output

Hello, World!
SHARED: 0x104970030 123
SHARED: 0x104988018 (null)

Process finished with exit code 0

main. c

#include "dynamic_lib.h"

#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>

extern char *SHARED;

int main() {
  printf("Hello, World!\n");

  SHARED = "123";
  printf("SHARED: %p %s\n", &SHARED, SHARED);

  void *handle = dlopen("libdynamic_lib.dylib", RTLD_NOW | RTLD_GLOBAL);
  assert(handle != NULL);

  void *sym = dlsym(handle, "dynamic_lib_func");
  assert(sym != NULL);

  ((void (*)(void))sym)();

  return 0;
}

dynamic_lib. c

#include "dynamic_lib.h"

#include "static_lib.h"

#include <stdio.h>

void dynamic_lib_func() {
  printf("SHARED: %p %s\n", &SHARED, SHARED);
}

static_lib. c

#include "static_lib.h"

char *SHARED; // adding = 0 doesn't change much

CMakeLists.txt

cmake_minimum_required(VERSION 3.13)
project(untitled1 C)

set(CMAKE_C_STANDARD 99)

add_library(static_lib STATIC static_lib.c)
add_library(dynamic_lib SHARED dynamic_lib.c)

target_link_libraries(dynamic_lib static_lib)

add_executable(untitled1 main.c)
target_link_libraries(untitled1 static_lib)

add_dependencies(untitled1 dynamic_lib)

Ответы [ 2 ]

1 голос
/ 28 января 2020

Проведение дополнительных экспериментов и настройка флагов компоновщика привели меня к некоторым другим вопросам SO, включая this и this .

Вместо -rdynamic, который работает на Linux, это то, что работает в macOS:

-undefined dynamic_lookup необходимо добавить к флагам компоновщика библиотеки Dynami c.

В моем примере это изменение следующим образом:

# It is important that we DO NOT link against static_lib and at the same time
# the -undefined dynamic_lookup is provided.
# target_link_libraries(dynamic_lib static_lib)
target_link_options(dynamic_lib PRIVATE -undefined dynamic_lookup)

Вывод, который я вижу сейчас:

Hello, World!
SHARED: 0x109ead030 123
SHARED: 0x109ead030 123

Process finished with exit code 0
0 голосов
/ 24 января 2020

И ваш основной исполняемый файл, и библиотека динамических c ссылок в static_lib.c. Поэтому у вас будет два экземпляра char *SHARED;. Если функции в библиотеке dynamici c будут использовать свой собственный экземпляр или использовать его для основного исполняемого файла, я бы предположил, что это зависит от реализации. В вашем случае это выглядит так, как будто он использует свой собственный.

Решение состоит в том, чтобы удалить char *SHARED; из основного исполняемого файла и сделать это после dlopen:

char **shared = dlsym(handle, "SHARED");
if (!shared)
  {
     perror("dlsym failed");
     exit(EXIT_FAILURE);
  }
*shared = "123";

Моя память из dlopen и dlsym немного ржавый, поэтому код может содержать незначительные ошибки.

Дополнительные комментарии

Не используйте assert для проверки возвращаемого значения из dlopen и dlsym. assert для обнаружения логических ошибок в вашем коде. Не рекомендуется для обнаружения других ошибок времени выполнения. В зависимости от вашей цепочки инструментов и настроек это может быть oop.

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

...