12 #include <pybind11/embed.h>
15 #include "config/config.h"
16 #include "utils/logger.hpp"
18 #define STRINGIFY(x) #x
19 #define TOSTRING(x) STRINGIFY(x)
21 namespace fs = std::filesystem;
25 namespace pybind_wrappers {
31 #if defined(NMODL_STATIC_PYWRAPPER)
35 "nmodl_init_pybind_wrapper_api"));
38 if (
init !=
nullptr) {
42 return init !=
nullptr;
50 std::string compiled_ver = fmt::format(
"{}.{}", PY_MAJOR_VERSION, PY_MINOR_VERSION);
51 auto pPy_GetVersion = (
const char* (*) (
void) )
dlsym(
RTLD_DEFAULT,
"Py_GetVersion");
52 if (pPy_GetVersion ==
nullptr) {
53 throw std::runtime_error(
"Unable to find the function `Py_GetVersion`");
55 const char* runtime_ver = pPy_GetVersion();
56 std::size_t len = compiled_ver.size();
57 if (std::strncmp(runtime_ver, compiled_ver.c_str(), len) != 0 ||
58 (runtime_ver[len] >=
'0' && runtime_ver[len] <=
'9')) {
59 throw std::runtime_error(
60 fmt::format(
"Python version mismatch. nmodl has been compiled with python {} and is "
61 "being run with python {}",
68 const auto pylib_env = std::getenv(
"NMODL_PYLIB");
70 logger->critical(
"NMODL_PYLIB environment variable must be set to load embedded python");
71 throw std::runtime_error(
"NMODL_PYLIB not set");
78 logger->critical(
"Tried but failed to load {}", pylib_env);
80 throw std::runtime_error(
"Failed to dlopen");
85 if (std::getenv(
"NMODLHOME") ==
nullptr) {
86 logger->critical(
"NMODLHOME environment variable must be set to load embedded python");
87 throw std::runtime_error(
"NMODLHOME not set");
89 auto pybind_wraplib_env = fs::path(std::getenv(
"NMODLHOME")) /
"lib" /
"libpywrapper";
91 if (!fs::exists(pybind_wraplib_env)) {
92 logger->critical(
"NMODLHOME doesn't contain libpywrapper{} library",
94 throw std::runtime_error(
"NMODLHOME doesn't have lib/libpywrapper library");
96 std::string env_str = pybind_wraplib_env.string();
100 logger->critical(
"Tried but failed to load {}", pybind_wraplib_env.string());
102 throw std::runtime_error(
"Failed to dlopen");
107 #if defined(NMODL_STATIC_PYWRAPPER)
112 "nmodl_init_pybind_wrapper_api"));
117 logger->critical(
"Tried but failed to load pybind wrapper symbols");
119 throw std::runtime_error(
"Failed to dlsym");
void * pybind_wrapper_handle
const pybind_wrap_api & api()
Get a pointer to the pybind_wrap_api struct.
DLFCN_EXPORT void * dlopen(const char *file, int mode)
DLFCN_EXPORT char * dlerror(void)
DLFCN_EXPORT int dlclose(void *handle)
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
decltype(&nmodl_init_pybind_wrapper_api) nmodl_init_pybind_wrapper_api_fpointer
void assert_compatible_python_versions()
NMODL_EXPORT pybind_wrap_api nmodl_init_pybind_wrapper_api() noexcept
encapsulates code generation backend implementations
static const std::string SHARED_LIBRARY_SUFFIX