Skip to content

Commit 6d0b470

Browse files
committed
Reimplement version check and combine init macros
This reimplements the version check to avoid sscanf (which has reportedly started throwing warnings under MSVC, even when used perfectly safely -- #1314). It also extracts the mostly duplicated parts of PYBIND11_MODULE/PYBIND11_PLUGIN into separate macros.
1 parent 9f41c8e commit 6d0b470

File tree

1 file changed

+29
-38
lines changed

1 file changed

+29
-38
lines changed

include/pybind11/detail/common.h

Lines changed: 29 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,31 @@ extern "C" {
211211
#define PYBIND11_TOSTRING(x) PYBIND11_STRINGIFY(x)
212212
#define PYBIND11_CONCAT(first, second) first##second
213213

214+
#define PYBIND11_CHECK_PYTHON_VERSION \
215+
{ \
216+
const char *compiled_ver = PYBIND11_TOSTRING(PY_MAJOR_VERSION) \
217+
"." PYBIND11_TOSTRING(PY_MINOR_VERSION); \
218+
const char *runtime_ver = Py_GetVersion(); \
219+
size_t len = std::strlen(compiled_ver); \
220+
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 \
221+
|| (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) { \
222+
PyErr_Format(PyExc_ImportError, \
223+
"Python version mismatch: module was compiled for Python %s, " \
224+
"but the interpreter version is incompatible: %s.", \
225+
compiled_ver, runtime_ver); \
226+
return nullptr; \
227+
} \
228+
}
229+
230+
#define PYBIND11_CATCH_INIT_EXCEPTIONS \
231+
catch (pybind11::error_already_set &e) { \
232+
PyErr_SetString(PyExc_ImportError, e.what()); \
233+
return nullptr; \
234+
} catch (const std::exception &e) { \
235+
PyErr_SetString(PyExc_ImportError, e.what()); \
236+
return nullptr; \
237+
} \
238+
214239
/** \rst
215240
***Deprecated in favor of PYBIND11_MODULE***
216241
@@ -230,27 +255,10 @@ extern "C" {
230255
PYBIND11_DEPRECATED("PYBIND11_PLUGIN is deprecated, use PYBIND11_MODULE") \
231256
static PyObject *pybind11_init(); \
232257
PYBIND11_PLUGIN_IMPL(name) { \
233-
int major, minor; \
234-
if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \
235-
PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \
236-
return nullptr; \
237-
} else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \
238-
PyErr_Format(PyExc_ImportError, \
239-
"Python version mismatch: module was compiled for " \
240-
"version %i.%i, while the interpreter is running " \
241-
"version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \
242-
major, minor); \
243-
return nullptr; \
244-
} \
258+
PYBIND11_CHECK_PYTHON_VERSION \
245259
try { \
246260
return pybind11_init(); \
247-
} catch (pybind11::error_already_set &e) { \
248-
PyErr_SetString(PyExc_ImportError, e.what()); \
249-
return nullptr; \
250-
} catch (const std::exception &e) { \
251-
PyErr_SetString(PyExc_ImportError, e.what()); \
252-
return nullptr; \
253-
} \
261+
} PYBIND11_CATCH_INIT_EXCEPTIONS \
254262
} \
255263
PyObject *pybind11_init()
256264

@@ -274,29 +282,12 @@ extern "C" {
274282
#define PYBIND11_MODULE(name, variable) \
275283
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
276284
PYBIND11_PLUGIN_IMPL(name) { \
277-
int major, minor; \
278-
if (sscanf(Py_GetVersion(), "%i.%i", &major, &minor) != 2) { \
279-
PyErr_SetString(PyExc_ImportError, "Can't parse Python version."); \
280-
return nullptr; \
281-
} else if (major != PY_MAJOR_VERSION || minor != PY_MINOR_VERSION) { \
282-
PyErr_Format(PyExc_ImportError, \
283-
"Python version mismatch: module was compiled for " \
284-
"version %i.%i, while the interpreter is running " \
285-
"version %i.%i.", PY_MAJOR_VERSION, PY_MINOR_VERSION, \
286-
major, minor); \
287-
return nullptr; \
288-
} \
285+
PYBIND11_CHECK_PYTHON_VERSION \
289286
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
290287
try { \
291288
PYBIND11_CONCAT(pybind11_init_, name)(m); \
292289
return m.ptr(); \
293-
} catch (pybind11::error_already_set &e) { \
294-
PyErr_SetString(PyExc_ImportError, e.what()); \
295-
return nullptr; \
296-
} catch (const std::exception &e) { \
297-
PyErr_SetString(PyExc_ImportError, e.what()); \
298-
return nullptr; \
299-
} \
290+
} PYBIND11_CATCH_INIT_EXCEPTIONS \
300291
} \
301292
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
302293

0 commit comments

Comments
 (0)