如何通过静态库(macOS)在主进程和动态库之间共享全局变量?
How to share a global variable between a main process and a dynamic library via a static library (macOS)?
我的问题似乎与这个问题类似,但在我的例子中,共享变量在静态库中,而且这个问题的建议对我没有帮助:Sharing global data between a shared library and main. Along the way I saw the issues from this question but no final solution either: OS X linker unable to find symbols from a C file which only contains variables.
我正在尝试让我的主进程和一个动态库dlopen
共享全局变量SHARED
,它位于一个共享库中,它们都link到.
我创建了一个 minimal project on GitHub 但我还在下面提供了该项目的内容。
问题: 我期望的输出是在两种情况下看到相同的变量和相同的地址。相反,我看到了 SHARED
变量的两个副本。
我的问题: 哪个编译和 linker 标志的组合可以删除 SHARED
变量的第二个实例,这样只有一个实例是在主进程和动态库之间正确共享。
其他背景
经过进一步研究,我认为这个问题可以简化为以下问题:如何获得 -rdynamic
标志的 Linux 行为?
这不是我的本意 运行 这样的代码。我正在移植 Linux 上 运行 的现有软件。该软件在其主进程和动态库之间共享全局变量。我已经验证它正在使用 -rdynamic
在 Linux 上实现这种行为:在 Linux 上,只需将 -rdynamic
添加到我的 linker 标志示例的可执行文件!使全局变量成为共享变量。
描述了我正在寻找的行为:
If you use "dlopen" to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself. ...
现在的问题是我无法在 macOS 上使用我的示例实现此行为。添加 -rdynamic
似乎没有它对 Linux.
的影响
输出
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)
您的主要可执行文件和 static_lib.c
中的动态库链接。因此,您将有两个 char *SHARED;
实例。如果动态库中的函数将使用它们自己的实例,或者使用主可执行文件的实例,我猜是依赖于实现的。在你的情况下,它看起来好像使用了它自己的。
解决方案是从主可执行文件中删除 char *SHARED;
并在 dlopen
:
之后执行此操作
char **shared = dlsym(handle, "SHARED");
if (!shared)
{
perror("dlsym failed");
exit(EXIT_FAILURE);
}
*shared = "123";
我对dlopen
和dlsym
的记忆有点生疏,所以代码可能有小错误。
补充评论
不要使用 assert
来测试来自 dlopen
和 dlsym
的 return 值。 assert
用于检测代码中的逻辑错误。不建议用于检测其他运行时错误。根据您的工具链和设置,它甚至可能是一个 noop。
不要使用全局变量与库函数通信。函数需要知道的一切都应该可以通过其函数参数访问。
做更多实验并调整链接器标志让我想到了其他一些 SO 问题,包括 this and this。
而不是在 Linux 上工作的 -rdynamic
,这是在 macOS 上工作的:
必须将 -undefined dynamic_lookup
添加到动态库的链接器标志中。
在我的例子中,变化如下:
# 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
我的问题似乎与这个问题类似,但在我的例子中,共享变量在静态库中,而且这个问题的建议对我没有帮助:Sharing global data between a shared library and main. Along the way I saw the issues from this question but no final solution either: OS X linker unable to find symbols from a C file which only contains variables.
我正在尝试让我的主进程和一个动态库dlopen
共享全局变量SHARED
,它位于一个共享库中,它们都link到.
我创建了一个 minimal project on GitHub 但我还在下面提供了该项目的内容。
问题: 我期望的输出是在两种情况下看到相同的变量和相同的地址。相反,我看到了 SHARED
变量的两个副本。
我的问题: 哪个编译和 linker 标志的组合可以删除 SHARED
变量的第二个实例,这样只有一个实例是在主进程和动态库之间正确共享。
其他背景
经过进一步研究,我认为这个问题可以简化为以下问题:如何获得 -rdynamic
标志的 Linux 行为?
这不是我的本意 运行 这样的代码。我正在移植 Linux 上 运行 的现有软件。该软件在其主进程和动态库之间共享全局变量。我已经验证它正在使用 -rdynamic
在 Linux 上实现这种行为:在 Linux 上,只需将 -rdynamic
添加到我的 linker 标志示例的可执行文件!使全局变量成为共享变量。
If you use "dlopen" to load a dynamic object which needs to refer back to the symbols defined by the program, rather than some other dynamic object, then you will probably need to use this option when linking the program itself. ...
现在的问题是我无法在 macOS 上使用我的示例实现此行为。添加 -rdynamic
似乎没有它对 Linux.
输出
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)
您的主要可执行文件和 static_lib.c
中的动态库链接。因此,您将有两个 char *SHARED;
实例。如果动态库中的函数将使用它们自己的实例,或者使用主可执行文件的实例,我猜是依赖于实现的。在你的情况下,它看起来好像使用了它自己的。
解决方案是从主可执行文件中删除 char *SHARED;
并在 dlopen
:
char **shared = dlsym(handle, "SHARED");
if (!shared)
{
perror("dlsym failed");
exit(EXIT_FAILURE);
}
*shared = "123";
我对dlopen
和dlsym
的记忆有点生疏,所以代码可能有小错误。
补充评论
不要使用 assert
来测试来自 dlopen
和 dlsym
的 return 值。 assert
用于检测代码中的逻辑错误。不建议用于检测其他运行时错误。根据您的工具链和设置,它甚至可能是一个 noop。
不要使用全局变量与库函数通信。函数需要知道的一切都应该可以通过其函数参数访问。
做更多实验并调整链接器标志让我想到了其他一些 SO 问题,包括 this and this。
而不是在 Linux 上工作的 -rdynamic
,这是在 macOS 上工作的:
必须将 -undefined dynamic_lookup
添加到动态库的链接器标志中。
在我的例子中,变化如下:
# 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