My question seems to be similar to this question however in my case the shared variable is in a static library and also the advice from this question didn't help me: 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.
I am trying to make my main process and a dynamic library that it dlopen
's to share the global variable SHARED
which is located in a shared library that they both link to.
I have created a minimal project on GitHub but I am also providing the contents of that project below.
The issue: The output I am expecting is to see the same variable and the same address in both cases. Instead I am seeing two copies of the SHARED
variable.
My question: which combination of compilation and linker flags could remove the second instance of the SHARED
variable so that only one instance would be properly shared between the main process and the dynamic library.
Additional background
After additional research, I think this question can be reduced to the following one: how to get the Linux behavior of the -rdynamic
flag?
This is not my intention to run the code like this. I am porting existing software that runs on Linux. That software shares global variables between its main process and the dynamic libraries. I have verified that it is using -rdynamic
to achieve this kind of behavior on Linux: on Linux, simply adding -rdynamic
to the linker flags of my example's executable does! make the global variable to become shared.
What exactly does -rdynamic
do and when exactly is it needed? describes the behavior that I am looking for:
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. ...
Now the problem is that I cannot achieve this behavior with my example on macOS. Adding -rdynamic
seems to not have the effect that it has on 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)