From 66ea34a76dad0141d7acaf2d22e268ea0db04d39 Mon Sep 17 00:00:00 2001 From: cnc Date: Sat, 6 Jun 2026 05:20:23 +0800 Subject: [PATCH] =?UTF-8?q?=E9=AA=8C=E8=AF=81=20Boost.Python=20shim=20?= =?UTF-8?q?=E6=83=B0=E6=80=A7=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/wasm_shims/python_c_api_probe_main.cc | 131 ++++++++++++++++++++- 1 file changed, 128 insertions(+), 3 deletions(-) diff --git a/core/wasm_shims/python_c_api_probe_main.cc b/core/wasm_shims/python_c_api_probe_main.cc index 65cbbac..1115637 100644 --- a/core/wasm_shims/python_c_api_probe_main.cc +++ b/core/wasm_shims/python_c_api_probe_main.cc @@ -1,12 +1,31 @@ +#include "boost/python/class.hpp" +#include "boost/python/converter/registry.hpp" +#include "boost/python/def.hpp" +#include "boost/python/dict.hpp" +#include "boost/python/enum.hpp" +#include "boost/python/exception_translator.hpp" +#include "boost/python/extract.hpp" +#include "boost/python/import.hpp" +#include "boost/python/list.hpp" +#include "boost/python/module.hpp" #include "boost/python/object.hpp" +#include "boost/python/object/class_detail.hpp" +#include "boost/python/return_internal_reference.hpp" +#include "boost/python/scope.hpp" +#include "boost/python/str.hpp" +#include "boost/python/suite/indexing/map_indexing_suite.hpp" +#include "boost/python/tuple.hpp" #include #include +#include +#include // LinuxCNC source basis: src/emc/rs274ngc/gcodemodule.cc, -// interpmodule.cc, and py*.cc use these Python C API entry points while -// defining RS274 Python binding objects. The WASM shim keeps the API inert -// and link-safe while browser Python execution remains disabled. +// interpmodule.cc, py*.cc, interp_python.cc, interp_namedparams.cc, and +// src/emc/pythonplugin/python_plugin.cc use these Python C API and +// Boost.Python entry points. The WASM shim keeps the API inert and link-safe +// while browser Python execution remains disabled. namespace { struct ProbeObject { @@ -14,8 +33,111 @@ struct ProbeObject { int value; }; +struct ProbeCppObject { + int value = 0; +}; + +PyObject *probe_getter(PyObject *, void *) { + return Py_None; +} + +int probe_setter(PyObject *, PyObject *, void *) { + return 0; +} + +PyObject *probe_method(PyObject *, PyObject *) { + return Py_None; +} + +void translate_probe_exception(const std::runtime_error &) { +} + +bool boost_python_shims_are_inert() { + namespace bp = boost::python; + + bp::object object; + if (object.ptr() != nullptr || object.attr("missing").operator bp::object().ptr() != nullptr || + object["missing"].ptr() != nullptr || object[0].ptr() != nullptr || + object().ptr() != nullptr) { + return false; + } + + bp::list list; + list.append(object); + list.extend(list); + bp::tuple tuple(list); + bp::dict dict; + if (bp::tuple().ptr() != nullptr || tuple.ptr() != nullptr || + bp::make_tuple(1, 2.0, "three").ptr() != nullptr || + dict.keys().ptr() != nullptr || bp::len(list) != 0) { + return false; + } + + if ((object % tuple).ptr() != nullptr || ("linuxcnc" % tuple).ptr() != nullptr || + (object + object).ptr() != nullptr || (object + "suffix").ptr() != nullptr || + ("prefix" + object).ptr() != nullptr) { + return false; + } + + bp::scope scope(object); + scope.attr("this") = object; + if (scope.attr("this").operator bp::object().ptr() != nullptr) { + return false; + } + + if (bp::getattr(object, "__next__").ptr() != nullptr || + bp::make_function(probe_method).ptr() != nullptr || + bp::make_getter(probe_getter).ptr() != nullptr || + bp::make_setter(probe_setter).ptr() != nullptr || + bp::import("traceback").ptr() != nullptr || + bp::str("\n").join(object).ptr() != nullptr) { + return false; + } + + if (static_cast(bp::extract(object)) != 0 || + static_cast(bp::extract(object)) != 0.0 || + static_cast(bp::extract(object)) != std::string() || + static_cast(bp::extract(object)) != nullptr) { + return false; + } + + bp::handle<> default_handle; + bp::handle<> null_handle(bp::allow_null(static_cast(nullptr))); + bp::handle<> borrowed_handle(bp::borrowed(Py_None)); + if (default_handle || default_handle.get() != nullptr || + null_handle || null_handle.get() != nullptr || + borrowed_handle || borrowed_handle.get() != nullptr) { + return false; + } + bp::handle_exception(); + + bp::class_("ProbeCppObject") + .def("method", probe_method) + .def_readwrite("value", &ProbeCppObject::value) + .add_property("property", bp::make_getter(probe_getter), bp::make_setter(probe_setter)); + bp::class_("ProbeCppObjectNoInit", bp::no_init); + bp::class_("ProbeCppObjectDoc", "doc"); + bp::class_("ProbeCppObjectDocNoInit", "doc", bp::no_init); + + bp::enum_("ProbeEnum").value("one", 1).export_values(); + bp::def("probe", probe_method); + bp::register_exception_translator(translate_probe_exception); + bp::return_internal_reference<1, bp::default_call_policies> reference_policy; + (void)reference_policy; + bp::map_indexing_suite> map_suite; + (void)map_suite; + if (bp::objects::registered_class_object(bp::type_id()) != nullptr) { + return false; + } + + return true; +} + } // namespace +BOOST_PYTHON_MODULE(cnc_sim_python_c_api_probe_module) { +} + int main() { if (Py_IsInitialized() != 1) { return 1; @@ -123,5 +245,8 @@ int main() { if (PyErr_Format(PyExc_TypeError, "linuxcnc") != nullptr) { return 15; } + if (!boost_python_shims_are_inert()) { + return 28; + } return 0; }