From 042267da74a2cc6e5052e55543a92e6a0396829a Mon Sep 17 00:00:00 2001 From: Richard Connon Date: Sun, 10 Dec 2023 10:58:38 +0000 Subject: [PATCH] Allow users to enable dlopenflags handling explicitly (GH-247) A new context manager `allow_lua_module_loading()` is added. Enabling module loading by default doesn't work when there are multiple Lua specific Lupa modules because the symbols collide with each other when loaded with `RTLD_GLOBAL`. Therefore, we disable the dlopenflags by default and allow users to conditionally enable them as part of the import. --- lupa/__init__.py | 47 +++++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/lupa/__init__.py b/lupa/__init__.py index c9d868bc..7b05b6e8 100644 --- a/lupa/__init__.py +++ b/lupa/__init__.py @@ -1,36 +1,47 @@ from __future__ import absolute_import +from contextlib import contextmanager as _contextmanager -# We need to enable global symbol visibility for lupa in order to -# support binary module loading in Lua. If we can enable it here, we -# do it temporarily. +# Find the implementation with the latest Lua version available. +_newest_lib = None + + +@_contextmanager +def allow_lua_module_loading(): + """ + A context manager for enabling binary Lua module loading when importing Lua. -def _try_import_with_global_library_symbols(): + This can only be used once within a Python runtime and must wrap the import of the + ``lupa.*`` Lua module, e.g.:: + + import lupa + with lupa.allow_lua_module_loading() + from lupa import lua54 + + lua = lua54.LuaRuntime() + lua.require('cjson') + """ try: from os import RTLD_NOW, RTLD_GLOBAL except ImportError: - from DLFCN import RTLD_NOW, RTLD_GLOBAL # Py2.7 + try: + from DLFCN import RTLD_NOW, RTLD_GLOBAL # Py2.7 + except ImportError: + # MS-Windows does not have dlopen-flags. + yield + return + dlopen_flags = RTLD_NOW | RTLD_GLOBAL import sys old_flags = sys.getdlopenflags() + try: sys.setdlopenflags(dlopen_flags) - import lupa._lupa + yield finally: sys.setdlopenflags(old_flags) -try: - _try_import_with_global_library_symbols() -except: - pass - -del _try_import_with_global_library_symbols - - -# Find the implementation with the latest Lua version available. -_newest_lib = None - def _import_newest_lib(): global _newest_lib @@ -52,8 +63,8 @@ def _import_newest_lib(): raise RuntimeError("Failed to import Lupa binary module.") # prefer Lua over LuaJIT and high versions over low versions. module_name = max(modules, key=lambda m: (m[1] == 'lua', tuple(map(int, m[2] or '0')))) - _newest_lib = __import__(module_name[0], level=1, fromlist="*", globals=globals()) + _newest_lib = __import__(module_name[0], level=1, fromlist="*", globals=globals()) return _newest_lib