如何通过静态库(macOS)在主进程和动态库之间共享全局变量?

如何通过静态库(macOS)在主进程和动态库之间共享全局变量?,c,linker,dynamic-library,C,Linker,Dynamic Library,我的问题似乎与此问题类似,但在我的情况下,共享变量位于静态库中,并且此问题的建议对我没有帮助:。一路上,我看到了这个问题的问题,但也没有最终的解决办法: 我试图使我的主进程和一个动态库dlopen共享全局变量SHARED,该变量位于它们都链接到的共享库中 我已经创建了一个项目,但我也提供了该项目的内容如下 问题:我期望的输出是在这两种情况下看到相同的变量和相同的地址。相反,我看到的是SHARED变量的两个副本 我的问题:编译和链接器标志的哪种组合可以删除SHARED变量的第二个实例,以便在主进程

我的问题似乎与此问题类似,但在我的情况下,共享变量位于静态库中,并且此问题的建议对我没有帮助:。一路上,我看到了这个问题的问题,但也没有最终的解决办法:

我试图使我的主进程和一个动态库
dlopen
共享全局变量
SHARED
,该变量位于它们都链接到的共享库中

我已经创建了一个项目,但我也提供了该项目的内容如下

问题:我期望的输出是在这两种情况下看到相同的变量和相同的地址。相反,我看到的是
SHARED
变量的两个副本

我的问题:编译和链接器标志的哪种组合可以删除
SHARED
变量的第二个实例,以便在主进程和动态库之间只正确共享一个实例

附加背景

经过进一步研究,我认为这个问题可以简化为以下问题:如何获得
-rdynamic
标志的Linux行为

我不打算这样运行代码。我正在移植在Linux上运行的现有软件。该软件在其主进程和动态库之间共享全局变量。我已经验证了它正在使用
-rdynamic
在Linux上实现这种行为:在Linux上,只需将
-rdynamic
添加到示例可执行文件的链接器标志中即可!使全局变量成为共享变量

描述我正在查找的行为:

如果使用“dlopen”加载需要引用程序定义的符号的动态对象,而不是其他动态对象,则在链接程序本身时可能需要使用此选项

现在的问题是,我无法用macOS上的示例实现这种行为。添加
-rdynamic
似乎没有在Linux上产生的效果

输出

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

Process finished with exit code 0
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)
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;
}
#include "dynamic_lib.h"

#include "static_lib.h"

#include <stdio.h>

void dynamic_lib_func() {
  printf("SHARED: %p %s\n", &SHARED, SHARED);
}
#include "static_lib.h"

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

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

Process finished with exit code 0
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)

主可执行文件和
static_lib.c
中的动态库链接。因此,您将有两个
char*共享的实例。如果动态库中的函数将使用它们自己的实例,或者将该实例用于主可执行文件,我想这取决于实现。在您的情况下,它看起来好像使用了自己的

解决方案是删除
char*SHARED并在
dlopen
之后执行此操作:

char **shared = dlsym(handle, "SHARED");
if (!shared)
  {
     perror("dlsym failed");
     exit(EXIT_FAILURE);
  }
*shared = "123";
我的
dlopen
dlsym
内存有点生锈,因此代码可能包含一些小错误

补充意见 不要使用
assert
测试
dlopen
dlsym
的返回值<代码>断言
用于检测代码中的逻辑错误。不建议将其用于检测其他运行时错误。根据您的工具链和设置,它甚至可能是一个noop


不要使用全局变量与库函数通信。函数需要知道的所有信息都应该可以通过函数参数访问

做了更多的实验,调整了链接器标志,这让我想到了其他一些SO问题,包括和

这不是在Linux上工作的
-rdynamic
,而是在macOS上工作的:

必须将
-未定义的动态\u查找
添加到动态库的链接器标志中

在我的示例中,更改如下:

# 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

谢谢你的回答。我花了一些时间去我的Linux机器上检查我的示例在Linux上是如何工作的。在Linux上,只需添加
-rdynamic
即可使全局变量成为共享变量。请再次查看我的问题:我在那里添加了其他信息。