This is an automated email from the ASF dual-hosted git repository. szaszm pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/nifi-minifi-cpp.git
commit e62b5bb1511882f93f3caf1f38fb6ed8c647b4d5 Author: Marton Szasz <[email protected]> AuthorDate: Mon Oct 28 16:44:03 2024 +0100 MINIFICPP-2480 workaround python version incompatibilities around 3.6 vs 3.11 Closes #1883 Signed-off-by: Marton Szasz <[email protected]> --- extensions/python/PythonInterpreter.cpp | 54 +++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 9 deletions(-) diff --git a/extensions/python/PythonInterpreter.cpp b/extensions/python/PythonInterpreter.cpp index 267db16fd..212aea705 100644 --- a/extensions/python/PythonInterpreter.cpp +++ b/extensions/python/PythonInterpreter.cpp @@ -18,6 +18,16 @@ #include "PythonBindings.h" +#ifndef WIN32 +#if !defined(__APPLE__) && !defined(_GNU_SOURCE) +#define _GNU_SOURCE // NOLINT: for RTLD_DEFAULT (source: `man dlsym` on linux) +#endif // !__APPLE__ && !_GNU_SOURCE +// on Apple, RTLD_DEFAULT is defined without needing any macros (source: `man dlsym` on macOS) +#include <dlfcn.h> +#endif // !WIN32 + +#include <regex> + namespace org::apache::nifi::minifi::extensions::python { Interpreter* Interpreter::getInterpreter() { @@ -34,30 +44,56 @@ GlobalInterpreterLock::~GlobalInterpreterLock() { } namespace { +struct version { + int major; + int minor; +}; + +std::optional<version> getPythonVersion() { + // example version: "3.0a5+ (py3k:63103M, May 12 2008, 00:53:55) \n[GCC 4.2.3]" + // "3.12.6 (main, Sep 8 2024, 13:18:56) [GCC 14.2.1 20240805]" + std::string ver_str = Py_GetVersion(); + std::smatch match; + if (std::regex_search(ver_str, match, std::regex{R"(^(\d+)\.(\d+))"})) { + return version{std::stoi(match[1]), std::stoi(match[2])}; + } else { + return std::nullopt; + } +} + // PyEval_InitThreads might be marked deprecated (depending on the version of Python.h) -// Python <= 3.6: This needs to be called manually after Py_Initialize to initialize threads +// Python <= 3.6: This needs to be called manually after Py_Initialize to initialize threads (python < 3.6 is unsupported by us) // Python >= 3.7: Noop function since its functionality is included in Py_Initialize // Python >= 3.9: Marked as deprecated (still noop) +// Python >= 3.11: removed // This can be removed if we drop the support for Python 3.6 void initThreads() { + using namespace std::literals; + // early return (skip workaround) above Python 3.6 + if (const auto version = getPythonVersion(); !version || (version->major == 3 && version->minor > 6) || version->major > 3) { + return; + } #if defined(__clang__) - #pragma clang diagnostic push +#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #elif defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" -#elif defined(WIN32) - #pragma warning(push) -#pragma warning(disable: 4996) #endif - if (!PyEval_ThreadsInitialized()) - PyEval_InitThreads(); +#ifndef WIN32 // dlsym hack, doesn't work on windows + // dlsym hack: allows us to build with python 3.11+, where these were removed (so no header declarations), and run with python 3.6 (e.g. RHEL8) + // the dlsym hack doesn't work on Windows, we'll drop python 3.6 support there + // lowercase, to avoid name conflicts with the header declaration, in case we're using an old enough python to build + const auto pyeval_threads_initialized = (int (*)())dlsym(RTLD_DEFAULT, "PyEval_ThreadsInitialized"); // NOLINT: C-style cast for POSIX-guaranteed dataptr -> funcptr conversion in dlsym + const auto pyeval_initthreads = (void (*)())dlsym(RTLD_DEFAULT, "PyEval_InitThreads"); // NOLINT: C-style cast for POSIX-guaranteed dataptr -> funcptr conversion in dlsym + gsl_Assert(pyeval_threads_initialized && pyeval_initthreads && "We're on python 3.6, yet we couldn't load PyEval_ThreadsInitialized and/or PyEval_InitThreads"); + if (!pyeval_threads_initialized()) + pyeval_initthreads(); +#endif // !WIN32 #if defined(__clang__) #pragma clang diagnostic pop #elif defined(__GNUC__) #pragma GCC diagnostic pop -#elif defined(WIN32) -#pragma warning(pop) #endif }
