2 #include <../../nrnconf.h>
31 extern void nrn_possible_mismatched_arch(
const char*);
34 #ifdef NRNPYTHON_DYNAMICLOAD
56 #ifdef NRNPYTHON_DYNAMICLOAD
57 static std::string nrnpy_pylib{}, nrnpy_pyversion{};
64 static std::string check_output(std::string command) {
65 std::FILE*
const p = popen(command.c_str(),
"r");
67 throw std::runtime_error(
"popen(" + command +
", \"r\") failed");
70 std::array<char, 1024> buffer{};
71 while (std::fgets(buffer.data(), buffer.size() - 1,
p)) {
72 output += buffer.data();
74 if (
auto const code = pclose(
p)) {
75 std::ostringstream err;
76 err <<
"'" << command <<
"' did not terminate cleanly, pclose returned non-zero (" << code
77 <<
") after the following output had been read:\n"
79 throw std::runtime_error(err.str());
89 return str.size() >=
suffix.size() &&
90 str.substr(str.size() -
suffix.size(), std::string_view::npos) ==
suffix;
113 static void set_nrnpylib() {
114 std::array<std::pair<std::string&, const char*>, 3> params{
115 {{nrnpy_pylib,
"NRN_PYLIB"},
117 {nrnpy_pyversion,
"NRN_PYTHONVERSION"}}};
118 auto const all_set = [¶ms]() {
119 return std::all_of(params.begin(), params.end(), [](
auto const&
p) {
120 return !p.first.empty();
125 for (
auto& [glob_var, env_var]: params) {
126 if (
const char*
v = std::getenv(env_var)) {
140 auto const command = []() -> std::string {
143 std::replace(bnrnhome.begin(), bnrnhome.end(),
'/',
'\\');
144 std::replace(fnrnhome.begin(), fnrnhome.end(),
'\\',
'/');
145 return bnrnhome + R
"(\mingw\usr\bin\bash )" + fnrnhome + "/bin/nrnpyenv.sh " +
153 std::istringstream cmd_stdout{check_output(command)};
158 auto const proc_line = [](std::string_view line,
auto& glob_var, std::string_view env_var) {
159 std::string_view
const suffix{
"\""};
160 auto const prefix =
"export " + std::string{env_var} +
"=\"";
162 line.remove_prefix(
prefix.size());
163 line.remove_suffix(
suffix.size());
164 if (!glob_var.empty() && glob_var != line) {
166 "WARNING: overriding {} = {} with {}\n", env_var, glob_var, line)
173 while (std::getline(cmd_stdout, line)) {
174 for (
auto& [glob_var, env_var]: params) {
175 proc_line(line, glob_var, env_var);
181 std::ostringstream err;
182 err <<
"After running nrnpyenv.sh (" << command <<
") with output:\n"
184 <<
"\nwe are still missing information about the Python to be loaded:\n"
186 <<
" nrnpy_pylib=" << nrnpy_pylib <<
'\n'
187 <<
" nrnpy_pyversion=" << nrnpy_pyversion <<
'\n';
188 throw std::runtime_error(err.str());
194 nrnmpi_str_broadcast_world(nrnpy_pylib, 0);
195 nrnmpi_str_broadcast_world(nrnpy_pyversion, 0);
212 #ifdef NRNPYTHON_DYNAMICLOAD
218 }
catch (std::exception
const& e) {
220 fmt::format(
"Could not determine Python library details: {}\n", e.what())
227 fmt::format(
"Could not dlopen NRN_PYLIB: {}\n", nrnpy_pylib).c_str());
229 nrn_possible_mismatched_arch(nrnpy_pylib.c_str());
236 reg_fn = load_nrnpython();
256 #ifdef NRNPYTHON_DYNAMICLOAD
258 std::string pyversion{};
261 auto const factor = (pv10 >= 100) ? 100 : 10;
264 if (nrnpy_pylib.empty() || nrnpy_pyversion.empty()) {
267 fmt::format(
"Do not know what Python to load [nrnpy_pylib={} nrnpy_pyversion={}]\n",
273 pyversion = nrnpy_pyversion;
277 auto const& supported_versions = neuron::config::supported_python_versions;
279 std::find(supported_versions.begin(), supported_versions.end(), pyversion);
280 if (iter == supported_versions.end()) {
283 fmt::format(
"Python {} is not supported by this NEURON installation (supported:",
286 for (
auto const& good_ver: supported_versions) {
287 Fprintf(stderr, fmt::format(
" {}", good_ver).c_str());
290 "). If you are seeing this message, your environment probably contains "
291 "NRN_PYLIB, NRN_PYTHONEXE and NRN_PYTHONVERSION settings that are "
292 "incompatible with this NEURON. Try unsetting them.\n");
298 name.append(neuron::config::shared_library_prefix);
299 name.append(
"nrnpython");
300 name.append(pyversion);
301 name.append(neuron::config::shared_library_suffix);
308 Fprintf(stderr, fmt::format(
"Could not load {}\n",
name).c_str());
316 fmt::format(
"Could not load registration function from {}\n",
name).c_str());
void class2oc(const char *, ctor_f *cons, dtor_f *destruct, Member_func *, Member_ret_obj_func *, Member_ret_str_func *)
DLFCN_EXPORT void * dlopen(const char *file, int mode)
DLFCN_NOINLINE DLFCN_EXPORT void * dlsym(void *handle, const char *name)
void hoc_retpushx(double x)
static bool ends_with(const std::string &haystack, const std::string &needle)
Check if haystack ends with needle.
static bool starts_with(const std::string &haystack, const std::string &needle)
Check if haystack starts with needle.
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
impl_ptrs methods
Collection of pointers to functions with python-version-specific implementations.
std::string to_string(const T &obj)
void(*)(neuron::python::impl_ptrs *) nrnpython_reg_real_t
void nrnpython_reg_real(neuron::python::impl_ptrs *)
Populate NEURON state with information from a specific Python.
void nrnpython_reg()
Load + register an nrnpython library for a specific Python version.
int nrn_is_python_extension
static void p_destruct(void *)
static void * p_cons(Object *)
int(* nrnpy_hoccommand_exec)(Object *)
int nrnmpi_numprocs_world
int find(const int, const int, const int, const int, const int)
static struct prefix prefix[]
Collection of pointers to functions with python-version-specific implementations.
int(* hoccommand_exec)(Object *)
int Fprintf(FILE *stream, const char *fmt, Args... args)
int Printf(const char *fmt, Args... args)