-
Notifications
You must be signed in to change notification settings - Fork 64
Description
This has been a long standing issue that shows up in projects with non-trivial / isolated C modules. I'm just finally getting around to actually writing up this problem
Right now, pybind_extension creates a shared library is using cc_binary(). This statically links all the dependencies, transitively. To complicate matters, it uses -Bsymbolic -- what this does is change how the shared library looks up symbols, giving preference to symbols within the shared library (which, because of the static linking, includes all dependencies).
The net effect is the resulting shared library can't participate in process-global state. For example, lets say there's a foo-plugins library, normally provided as libfoo-plugins.so, with the intent that consumers can load the library and register plugins into a static map<...> PLUGINS that is global to the process. Now we create a mybind.so Python C module using pybind_extension, which depends on foo-plugins. Because of how it's linked in, mybind.so has its own private copy of the PLUGINS map. Later, when people start registering plugins and asking which are available, they'll get different answers depending on if they're within mybind.so or outside it.
Such globals aren't uncommon. Absl flags and module initializers are such an example, but are easily found in other C++ libraries.
The fix I suggest is to switch pybind_extension to using something like cc_shared_library, which provides some control over what is statically vs dynamically linked into the Python C module. cc_shared_library is annoying to use, but it can get the job done.
In any case, there needs to be a way to better control what is statically vs dynamically linked into the pybind_extension module.