diff --git a/CMakeLists.txt b/CMakeLists.txt index 36e6675..502012b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,6 +91,12 @@ endif() option(MAGNUM_BUILD_TESTS "Build unit tests" OFF) +if(MAGNUM_BUILD_STATIC AND UNIX) + # See src/python/corrade/__init__.py.in and the corresponding CMakeLists + # for details + option(MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL "Build Python bindings linking to static libraries with RTLD_GLOBAL enabled for loading" ON) +endif() + # Backwards compatibility for unprefixed CMake options. If the user isn't # explicitly using prefixed options in the first run already, accept the # unprefixed options, and remember this decision for subsequent runs diff --git a/doc/python/pages/building.rst b/doc/python/pages/building.rst index 4976498..b9693d1 100644 --- a/doc/python/pages/building.rst +++ b/doc/python/pages/building.rst @@ -150,14 +150,31 @@ containing location of all built libraries for use with Python setuptools: In case Corrade or Magnum is built with :dox:`CORRADE_BUILD_STATIC` / :dox:`MAGNUM_BUILD_STATIC`, the corresponding bindings are compiled into a -single dynamic module instead of one module per Corrade/Magnum library. In this -case, similarly to linking static plugins to Magnum's own command-line +single dynamic module instead of one module per Corrade/Magnum library. + +In this case, similarly to linking static plugins to Magnum's own command-line utilities, you can use the ``MAGNUM_PYTHON_BINDINGS_STATIC_PLUGINS`` CMake variable to link static plugins to the Python module, assuming Magnum, Magnum Plugins and Magnum Bindings are all CMake subprojects. It's a semicolon-separated list of existing CMake targets, for example ``Magnum::AnyImageImporter;MagnumPlugins::StbImageImporter``. +On Unix platforms, Python by default loads the modules in isolated namespaces. +That's a good thing to do from a security point of view, nevertheless with +static builds of Corrade and Magnum it will result in globals duplicated across +the Corrade and Magnum modules (and also any other Python modules that +use Magnum natively inside) unable to see each other in order to deduplicate +themselves, causing strange issues. To solve that, the +``MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL`` CMake option, which is enabled by +default on static builds on Unix platforms, overrides Python's module loading +code to not load them in isolated namespaces using :ref:`sys.setdlopenflags()`. +The override then happens inside :py:`import corrade` and is in effect for the +rest of the interpreter lifetime, to affect also any potential other modules +depending on Magnum loaded later. See also +:dox:`CORRADE_BUILD_STATIC_UNIQUE_GLOBALS` and +:dox:`MAGNUM_BUILD_STATIC_UNIQUE_GLOBALS` in Corrade and Magnum for more +information. + `Running unit tests`_ --------------------- diff --git a/doc/python/pages/changelog.rst b/doc/python/pages/changelog.rst index 4c610e1..4c31378 100644 --- a/doc/python/pages/changelog.rst +++ b/doc/python/pages/changelog.rst @@ -176,6 +176,12 @@ Changelog - Added a ``MAGNUM_PYTHON_BINDINGS_STATIC_PLUGINS`` CMake option for linking static plugins to the Python bindings module. See the :ref:`building documentation ` for more information. +- Added a ``MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL`` CMake option to make + the Python bindings module loaded into the global namespace instead of + isolated in order to attempt to solve problems with duplicated globals when + static builds of Corrade and Magnum are linked into multiple dynamic + modules. See the :ref:`building documentation ` for more + information. `2020.06`_ ========== diff --git a/src/python/corrade/CMakeLists.txt b/src/python/corrade/CMakeLists.txt index aa61aa9..7d87b04 100644 --- a/src/python/corrade/CMakeLists.txt +++ b/src/python/corrade/CMakeLists.txt @@ -84,7 +84,9 @@ if(NOT CORRADE_BUILD_STATIC) # Otherwise put it all into one library so it's easier to install (which is the # point of static builds). It also nicely avoids problems with multiply-defined -# global data. +# global data. Unless the static libraries are linked into multiple Python +# modules, that is, which is (on Unix at least) attempted to be solved by the +# MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL option below. else() configure_file(${CMAKE_CURRENT_SOURCE_DIR}/staticconfigure.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/staticconfigure.h) @@ -102,6 +104,16 @@ else() endif() endif() +# If the option is enabled, the setdlopenflags() code in __init__.py is used, +# otherwise it's commented out +if(MAGNUM_BUILD_STATIC AND UNIX AND MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL) + set(_MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL "") +else() + set(_MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL "## ") +endif() +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/__init__.py.in + ${CMAKE_CURRENT_BINARY_DIR}/__init__.py) + pybind11_add_module(corrade ${pybind11_add_module_SYSTEM} ${corrade_SRCS}) target_include_directories(corrade PRIVATE ${PROJECT_SOURCE_DIR}/src @@ -113,7 +125,7 @@ set_target_properties(corrade PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${output_dir}) file(GENERATE OUTPUT ${output_dir}/corrade/__init__.py - INPUT ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py) + INPUT ${CMAKE_CURRENT_BINARY_DIR}/__init__.py) if(MAGNUM_BUILD_TESTS) add_subdirectory(test) diff --git a/src/python/corrade/__init__.py b/src/python/corrade/__init__.py.in similarity index 83% rename from src/python/corrade/__init__.py rename to src/python/corrade/__init__.py.in index c5dc549..db77d70 100644 --- a/src/python/corrade/__init__.py +++ b/src/python/corrade/__init__.py.in @@ -25,6 +25,14 @@ """Root Corrade module""" +# If MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL is enabled in CMake, the lines +# below are included, otherwise they are commented out. What it does is a +# futile attempt to make Corrade (and Magnum) built as static libraries work +# together when built into multiple dynamic Python modules. +${_MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL}import sys +${_MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL}import ctypes +${_MAGNUM_BUILD_PYTHON_BINDINGS_RTLD_GLOBAL}sys.setdlopenflags(sys.getdlopenflags()|ctypes.RTLD_GLOBAL) + # On Windows, if a known directory layout is detected, add paths containing # binaries to the DLL search path import platform @@ -59,3 +67,5 @@ __all__ = [ # to globals and this would likely cause conflicts (magnum also defines # BUILD_*) ] + +# kate: hl python