From 8f2b707d026597018333ac60e707e5ab78c25a91 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 23 Jul 2020 18:35:18 +0200 Subject: [PATCH] Initial conversion to pybind11 --- CMakeLists.txt | 57 +------------ common/handle_error.cc | 32 +++---- common/pybindings.cc | 64 +++++++------- common/pybindings.h | 13 ++- common/pycontainers.h | 170 +++++++++++++++++-------------------- common/pywrappers.h | 52 +++++------- ecp5/arch_pybindings.cc | 34 ++++---- generic/arch_pybindings.cc | 70 +++++++-------- ice40/arch_pybindings.cc | 36 ++++---- 9 files changed, 223 insertions(+), 305 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 78c72b53..9591c216 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,17 +45,9 @@ if (STATIC_BUILD) set(CMAKE_CXX_FLAGS_RELEASE "/MT") set(CMAKE_CXX_FLAGS_DEBUG "/MTd") endif() - if (BUILD_PYTHON) - add_definitions(-DBOOST_PYTHON_STATIC_LIB) - endif() else() set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".so") set(link_param "-static") - if (BUILD_PYTHON) - find_package(ZLIB) - find_package(EXPAT) - find_package(Threads) - endif() endif() endif() @@ -173,54 +165,7 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h ) -if (BUILD_PYTHON) - # Find Boost::Python of a suitable version in a cross-platform way - # Some distributions (Arch) call it libboost_python3, others such as Ubuntu - # call it libboost_python35. In the latter case we must consider all minor versions - # Original source: https://github.com/BVLC/caffe/blob/master/cmake/Dependencies.cmake#L148 - set(version ${PYTHONLIBS_VERSION_STRING}) - - STRING(REGEX REPLACE "[^0-9]" "" boost_py_version "${version}") - find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs}) - set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) - - while (NOT "${version}" STREQUAL "" AND NOT Boost_PYTHON_FOUND) - STRING(REGEX REPLACE "([0-9.]+).[0-9]+" "\\1" version "${version}") - - STRING(REGEX REPLACE "[^0-9]" "" boost_py_version "${version}") - find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs}) - set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) - - STRING(REGEX MATCHALL "([0-9.]+).[0-9]+" has_more_version "${version}") - if ("${has_more_version}" STREQUAL "") - break() - endif () - endwhile () - - if (NOT Boost_PYTHON_FOUND) - foreach (PyVer 3 36 37 38 39) - find_package(Boost QUIET COMPONENTS python${PyVer} ${boost_libs}) - if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) - set(Boost_PYTHON_FOUND TRUE) - break() - endif () - endforeach () - endif () - - if (NOT Boost_PYTHON_FOUND) - STRING(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" gentoo_version "${PYTHONLIBS_VERSION_STRING}") - find_package(Boost QUIET COMPONENTS python-${gentoo_version} ${boost_libs}) - if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) - set(Boost_PYTHON_FOUND TRUE) - endif () - endif () - - if (NOT Boost_PYTHON_FOUND ) - message( FATAL_ERROR "No version of Boost::Python 3.x could be found.") - endif () -endif() - -include_directories(common/ json/ frontend/ 3rdparty/json11/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) +include_directories(common/ json/ frontend/ 3rdparty/json11/ 3rdparty/pybind11/include ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) if(BUILD_HEAP) find_package (Eigen3 REQUIRED NO_MODULE) diff --git a/common/handle_error.cc b/common/handle_error.cc index a091f07e..d5542369 100644 --- a/common/handle_error.cc +++ b/common/handle_error.cc @@ -1,10 +1,10 @@ #ifndef NO_PYTHON #include -#include +#include #include "nextpnr.h" -namespace py = boost::python; +namespace py = pybind11; NEXTPNR_NAMESPACE_BEGIN @@ -20,42 +20,36 @@ std::string parse_python_exception() std::string ret("Unfetchable Python error"); // If the fetch got a type pointer, parse the type into the exception string if (type_ptr != NULL) { - py::handle<> h_type(type_ptr); - py::str type_pstr(h_type); - // Extract the string from the boost::python object - py::extract e_type_pstr(type_pstr); + py::object obj = py::reinterpret_borrow(type_ptr); // If a valid string extraction is available, use it // otherwise use fallback - if (e_type_pstr.check()) - ret = e_type_pstr(); + if (py::isinstance(obj)) + ret = obj.cast(); else ret = "Unknown exception type"; } // Do the same for the exception value (the stringification of the // exception) if (value_ptr != NULL) { - py::handle<> h_val(value_ptr); - py::str a(h_val); - py::extract returned(a); - if (returned.check()) - ret += ": " + returned(); + py::object obj = py::reinterpret_borrow(value_ptr); + if (py::isinstance(obj)) + ret += ": " + obj.cast(); else ret += std::string(": Unparseable Python error: "); } // Parse lines from the traceback using the Python traceback module if (traceback_ptr != NULL) { - py::handle<> h_tb(traceback_ptr); + py::handle h_tb(traceback_ptr); // Load the traceback module and the format_tb function - py::object tb(py::import("traceback")); + py::object tb(py::module::import("traceback")); py::object fmt_tb(tb.attr("format_tb")); // Call format_tb to get a list of traceback strings py::object tb_list(fmt_tb(h_tb)); // Join the traceback strings into a single string - py::object tb_str(py::str("\n").join(tb_list)); + py::object tb_str(py::str("\n") + tb_list); // Extract the string, check the extraction, and fallback in necessary - py::extract returned(tb_str); - if (returned.check()) - ret += ": " + returned(); + if (py::isinstance(tb_str)) + ret += ": " + tb_str.cast(); else ret += std::string(": Unparseable Python traceback"); } diff --git a/common/pybindings.cc b/common/pybindings.cc index 51da00e9..49acb996 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -43,7 +43,7 @@ NEXTPNR_NAMESPACE_BEGIN // Architecture-specific bindings should be created in the below function, which // must be implemented in all architectures -void arch_wrap_python(); +void arch_wrap_python(py::module &m); bool operator==(const PortRef &a, const PortRef &b) { return (a.cell == b.cell) && (a.port == b.port); } @@ -90,13 +90,13 @@ template <> struct string_converter } // namespace PythonConversion -BOOST_PYTHON_MODULE(MODULE_NAME) +PYBIND11_MODULE(MODULE_NAME, m) { - register_exception_translator(&translate_assertfail); + //register_exception_translator(&translate_assertfail); using namespace PythonConversion; - enum_("GraphicElementType") + py::enum_(m, "GraphicElementType") .value("TYPE_NONE", GraphicElement::TYPE_NONE) .value("TYPE_LINE", GraphicElement::TYPE_LINE) .value("TYPE_ARROW", GraphicElement::TYPE_ARROW) @@ -105,7 +105,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .value("TYPE_LABEL", GraphicElement::TYPE_LABEL) .export_values(); - enum_("GraphicElementStyle") + py::enum_(m, "GraphicElementStyle") .value("STYLE_GRID", GraphicElement::STYLE_GRID) .value("STYLE_FRAME", GraphicElement::STYLE_FRAME) .value("STYLE_HIDDEN", GraphicElement::STYLE_HIDDEN) @@ -113,9 +113,11 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .value("STYLE_ACTIVE", GraphicElement::STYLE_ACTIVE) .export_values(); - class_("GraphicElement") - .def(init( - (args("type"), "style", "x1", "y1", "x2", "y2", "z"))) + py::class_(m, "GraphicElement") + .def(py::init( + //FIXME + //(args("type"), "style", "x1", "y1", "x2", "y2", "z") + )) .def_readwrite("type", &GraphicElement::type) .def_readwrite("x1", &GraphicElement::x1) .def_readwrite("y1", &GraphicElement::y1) @@ -123,13 +125,13 @@ BOOST_PYTHON_MODULE(MODULE_NAME) .def_readwrite("y2", &GraphicElement::y2) .def_readwrite("text", &GraphicElement::text); - enum_("PortType") + py::enum_(m, "PortType") .value("PORT_IN", PORT_IN) .value("PORT_OUT", PORT_OUT) .value("PORT_INOUT", PORT_INOUT) .export_values(); - enum_("PlaceStrength") + py::enum_(m, "PlaceStrength") .value("STRENGTH_NONE", STRENGTH_NONE) .value("STRENGTH_WEAK", STRENGTH_WEAK) .value("STRENGTH_STRONG", STRENGTH_STRONG) @@ -143,15 +145,15 @@ BOOST_PYTHON_MODULE(MODULE_NAME) typedef std::unordered_map IdIdMap; typedef std::unordered_map> RegionMap; - class_("BaseCtx", no_init); + py::class_>(m, "BaseCtx"); - auto loc_cls = class_("Loc") - .def(init()) + auto loc_cls = py::class_(m, "Loc") + .def(py::init()) .def_readwrite("x", &Loc::x) .def_readwrite("y", &Loc::y) .def_readwrite("z", &Loc::z); - auto ci_cls = class_>("CellInfo", no_init); + auto ci_cls = py::class_>(m, "CellInfo"); readwrite_wrapper, conv_from_str>::def_wrap(ci_cls, "name"); readwrite_wrapper, @@ -185,7 +187,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) fn_wrapper_1a_v>::def_wrap(ci_cls, "unsetAttr"); - auto pi_cls = class_>("PortInfo", no_init); + auto pi_cls = py::class_>(m, "PortInfo"); readwrite_wrapper, conv_from_str>::def_wrap(pi_cls, "name"); readonly_wrapper>::def_wrap(pi_cls, @@ -198,7 +200,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) typedef std::unordered_set BelSet; typedef std::unordered_set WireSet; - auto ni_cls = class_>("NetInfo", no_init); + auto ni_cls = py::class_>(m, "NetInfo"); readwrite_wrapper, conv_from_str>::def_wrap(ni_cls, "name"); readwrite_wrapper, @@ -208,7 +210,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readonly_wrapper>::def_wrap(ni_cls, "wires"); - auto pr_cls = class_>("PortRef", no_init); + auto pr_cls = py::class_>(m, "PortRef"); readonly_wrapper>::def_wrap(pr_cls, "cell"); readwrite_wrapper, @@ -216,16 +218,16 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readwrite_wrapper, pass_through>::def_wrap(pr_cls, "budget"); - auto pm_cls = class_>("PipMap", no_init); + auto pm_cls = py::class_>(m, "PipMap"); readwrite_wrapper, conv_from_str>::def_wrap(pm_cls, "pip"); readwrite_wrapper, pass_through>::def_wrap(pm_cls, "strength"); - def("parse_json", parse_json_shim); - def("load_design", load_design_shim, return_value_policy()); + m.def("parse_json", parse_json_shim); + m.def("load_design", load_design_shim, py::return_value_policy::take_ownership); - auto region_cls = class_>("Region", no_init); + auto region_cls = py::class_>(m, "Region"); readwrite_wrapper, conv_from_str>::def_wrap(region_cls, "name"); readwrite_wrapper, @@ -239,7 +241,7 @@ BOOST_PYTHON_MODULE(MODULE_NAME) readonly_wrapper>::def_wrap(region_cls, "wires"); - auto hierarchy_cls = class_>("HierarchicalCell", no_init); + auto hierarchy_cls = py::class_>(m, "HierarchicalCell"); readwrite_wrapper, conv_from_str>::def_wrap(hierarchy_cls, "name"); readwrite_wrapper>::def_wrap(hierarchy_cls, "nets"); readonly_wrapper>::def_wrap(hierarchy_cls, "hier_cells"); - WRAP_MAP(AttrMap, conv_to_str, "AttrMap"); - WRAP_MAP(PortMap, wrap_context, "PortMap"); - WRAP_MAP(IdIdMap, conv_to_str, "IdIdMap"); - WRAP_MAP(WireMap, wrap_context, "WireMap"); - WRAP_MAP_UPTR(RegionMap, "RegionMap"); + WRAP_MAP(m, AttrMap, conv_to_str, "AttrMap"); + WRAP_MAP(m, PortMap, wrap_context, "PortMap"); + WRAP_MAP(m, IdIdMap, conv_to_str, "IdIdMap"); + WRAP_MAP(m, WireMap, wrap_context, "WireMap"); + WRAP_MAP_UPTR(m, RegionMap, "RegionMap"); - WRAP_VECTOR(PortRefVector, wrap_context); + WRAP_VECTOR(m, PortRefVector, wrap_context); - arch_wrap_python(); + arch_wrap_python(m); } #ifdef MAIN_EXECUTABLE @@ -291,7 +293,7 @@ void init_python(const char *executable, bool first) PyImport_ImportModule(TOSTRING(MODULE_NAME)); PyRun_SimpleString("from " TOSTRING(MODULE_NAME) " import *"); - } catch (boost::python::error_already_set const &) { + } catch (py::error_already_set const &) { // Parse and output the exception std::string perror_str = parse_python_exception(); std::cout << "Error in Python: " << perror_str << std::endl; @@ -321,7 +323,7 @@ void execute_python_file(const char *python_file) if (result == -1) { log_error("Error occurred while executing Python script %s\n", python_file); } - } catch (boost::python::error_already_set const &) { + } catch (py::error_already_set const &) { // Parse and output the exception std::string perror_str = parse_python_exception(); log_error("Error in Python: %s\n", perror_str.c_str()); diff --git a/common/pybindings.h b/common/pybindings.h index c4d84442..4923c821 100644 --- a/common/pybindings.h +++ b/common/pybindings.h @@ -22,11 +22,10 @@ #define COMMON_PYBINDINGS_H #include -#include -#include -#include +#include #include #include +#include #include "pycontainers.h" #include "pywrappers.h" @@ -34,7 +33,7 @@ NEXTPNR_NAMESPACE_BEGIN -using namespace boost::python; +namespace py = pybind11; std::string parse_python_exception(); @@ -46,9 +45,9 @@ template void python_export_global(const char *name, Tn &x) return; d = PyModule_GetDict(m); try { - PyObject *p = incref(object(boost::ref(x)).ptr()); - PyDict_SetItemString(d, name, p); - } catch (boost::python::error_already_set const &) { + py::object obj = py::cast(x); + PyDict_SetItemString(d, name, obj.ptr()); + } catch (py::error_already_set const &) { // Parse and output the exception std::string perror_str = parse_python_exception(); std::cout << "Error in Python: " << perror_str << std::endl; diff --git a/common/pycontainers.h b/common/pycontainers.h index 2b9ee208..15e502d1 100644 --- a/common/pycontainers.h +++ b/common/pycontainers.h @@ -21,9 +21,7 @@ #ifndef COMMON_PYCONTAINERS_H #define COMMON_PYCONTAINERS_H -#include -#include -#include +#include #include #include #include @@ -33,12 +31,12 @@ NEXTPNR_NAMESPACE_BEGIN -using namespace boost::python; +namespace py = pybind11; inline void KeyError() { PyErr_SetString(PyExc_KeyError, "Key not found"); - boost::python::throw_error_already_set(); + throw py::error_already_set(); } /* @@ -47,7 +45,7 @@ pair containing (current, end), wrapped in a ContextualWrapp */ -template > struct iterator_wrapper +template > struct iterator_wrapper { typedef decltype(*(std::declval())) value_t; @@ -62,16 +60,13 @@ template (python_name, no_init).def("__next__", next, P()); + py::class_(m, python_name).def("__next__", next, P); } }; @@ -81,7 +76,7 @@ and end() which return iterator-like objects supporting ++, * and != Full STL iterator semantics are not required, unlike the standard Boost wrappers */ -template , +template > struct range_wrapper { @@ -110,23 +105,23 @@ struct range_wrapper return ss.str(); } - static void wrap(const char *range_name, const char *iter_name) + static void wrap(py::module &m, const char *range_name, const char *iter_name) { - class_(range_name, no_init).def("__iter__", iter).def("__repr__", repr); - iterator_wrapper().wrap(iter_name); + py::class_(m, range_name).def("__iter__", iter).def("__repr__", repr); + iterator_wrapper().wrap(m, iter_name); } typedef iterator_wrapper iter_wrap; }; -#define WRAP_RANGE(t, conv) \ - range_wrapper, conv>().wrap(#t "Range", #t "Iterator") +#define WRAP_RANGE(m, t, conv) \ + range_wrapper().wrap(m, #t "Range", #t "Iterator") /* A wrapper for a vector or similar structure. With support for conversion */ -template , +template > struct vector_wrapper { @@ -163,21 +158,21 @@ struct vector_wrapper return value_conv()(range.ctx, boost::ref(range.base.at(i))); } - static void wrap(const char *range_name, const char *iter_name) + static void wrap(py::module &m, const char *range_name, const char *iter_name) { - class_(range_name, no_init) + py::class_(m, range_name) .def("__iter__", iter) .def("__repr__", repr) .def("__len__", len) .def("__getitem__", getitem); - iterator_wrapper().wrap(iter_name); + iterator_wrapper().wrap(m, iter_name); } typedef iterator_wrapper iter_wrap; }; -#define WRAP_VECTOR(t, conv) vector_wrapper, conv>().wrap(#t, #t "Iterator") +#define WRAP_VECTOR(m, t, conv) vector_wrapper().wrap(m, #t, #t "Iterator") /* Wrapper for a pair, allows accessing either using C++-style members (.first and @@ -189,58 +184,55 @@ template struct pair_wrapper struct pair_iterator_wrapper { - static object next(std::pair &iter) + static py::object next(std::pair &iter) { if (iter.second == 0) { iter.second++; - return object(iter.first.first); + return py::cast(iter.first.first); } else if (iter.second == 1) { iter.second++; - return object(iter.first.second); + return py::cast(iter.first.second); } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); - boost::python::throw_error_already_set(); - // Should be unreachable, but prevent control may reach end of - // non-void - throw std::runtime_error("unreachable"); + throw py::error_already_set(); } } - static void wrap(const char *python_name) + static void wrap(py::module &m, const char *python_name) { - class_>(python_name, no_init).def("__next__", next); + py::class_>(m, python_name).def("__next__", next); } }; - static object get(T &x, int i) + static py::object get(T &x, int i) { if ((i >= 2) || (i < 0)) KeyError(); - return (i == 1) ? object(x.second) : object(x.first); + return (i == 1) ? py::object(x.second) : py::object(x.first); } - static void set(T &x, int i, object val) + static void set(T &x, int i, py::object val) { if ((i >= 2) || (i < 0)) KeyError(); if (i == 0) - x.first = extract(val); + x.first = val.cast(); if (i == 1) - x.second = extract(val); + x.second = val.cast(); } static int len(T &x) { return 2; } static std::pair iter(T &x) { return std::make_pair(boost::ref(x), 0); }; - static void wrap(const char *pair_name, const char *iter_name) + static void wrap(py::module &m, const char *pair_name, const char *iter_name) { - pair_iterator_wrapper::wrap(iter_name); - class_(pair_name, no_init) + pair_iterator_wrapper::wrap(m, iter_name); + py::class_(m, pair_name) .def("__iter__", iter) .def("__len__", len) .def("__getitem__", get) - .def("__setitem__", set, with_custodian_and_ward<1, 2>()) + .def("__setitem__", set, py::keep_alive<1, 2>()) .def_readwrite("first", &T::first) .def_readwrite("second", &T::second); } @@ -257,36 +249,34 @@ template struct map_pair_wrapper struct pair_iterator_wrapper { - static object next(std::pair &iter) + static py::object next(std::pair &iter) { if (iter.second == 0) { iter.second++; - return object(PythonConversion::string_converter().to_str( + return py::cast(PythonConversion::string_converter().to_str( iter.first.ctx, iter.first.base.first)); } else if (iter.second == 1) { iter.second++; - return object(value_conv()(iter.first.ctx, iter.first.base.second)); + return py::cast(value_conv()(iter.first.ctx, iter.first.base.second)); } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); - boost::python::throw_error_already_set(); - // Should be unreachable, but prevent control may reach end of - // non-void - throw std::runtime_error("unreachable"); + throw py::error_already_set(); } } - static void wrap(const char *python_name) + static void wrap(py::module &m, const char *python_name) { - class_>(python_name, no_init).def("__next__", next); + //FIXME + //py::class_>(m, python_name).def("__next__", next); } }; - static object get(wrapped_pair &x, int i) + static py::object get(wrapped_pair &x, int i) { if ((i >= 2) || (i < 0)) KeyError(); - return (i == 1) ? object(value_conv()(x.ctx, x.base.second)) - : object(PythonConversion::string_converter().to_str(x.ctx, + return (i == 1) ? py::cast(value_conv()(x.ctx, x.base.second)) + : py::cast(PythonConversion::string_converter().to_str(x.ctx, x.base.first)); } @@ -301,15 +291,15 @@ template struct map_pair_wrapper static typename value_conv::ret_type second_getter(wrapped_pair &t) { return value_conv()(t.ctx, t.base.second); } - static void wrap(const char *pair_name, const char *iter_name) + static void wrap(py::module &m, const char *pair_name, const char *iter_name) { - pair_iterator_wrapper::wrap(iter_name); - class_(pair_name, no_init) + pair_iterator_wrapper::wrap(m, iter_name); + py::class_(m, pair_name) .def("__iter__", iter) .def("__len__", len) .def("__getitem__", get) - .add_property("first", first_getter) - .add_property("second", second_getter); + .def_property_readonly("first", first_getter) + .def_property_readonly("second", second_getter); } }; @@ -358,17 +348,17 @@ template struct map_wrapper return x.base.count(k); } - static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) + static void wrap(py::module &m, const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) { - map_pair_wrapper::wrap(kv_name, kv_iter_name); - typedef range_wrapper, PythonConversion::wrap_context> rw; - typename rw::iter_wrap().wrap(iter_name); - class_(map_name, no_init) + map_pair_wrapper::wrap(m, kv_name, kv_iter_name); + typedef range_wrapper> rw; + typename rw::iter_wrap().wrap(m, iter_name); + py::class_(m, map_name) .def("__iter__", rw::iter) .def("__len__", len) .def("__contains__", contains) .def("__getitem__", get) - .def("__setitem__", set, with_custodian_and_ward<1, 2>()); + .def("__setitem__", set, py::keep_alive<1, 2>()); } }; @@ -383,36 +373,34 @@ template struct map_pair_wrapper_uptr struct pair_iterator_wrapper { - static object next(std::pair &iter) + static py::object next(std::pair &iter) { if (iter.second == 0) { iter.second++; - return object(PythonConversion::string_converter().to_str( + return py::cast(PythonConversion::string_converter().to_str( iter.first.ctx, iter.first.base.first)); } else if (iter.second == 1) { iter.second++; - return object(PythonConversion::ContextualWrapper(iter.first.ctx, *iter.first.base.second.get())); + return py::cast(PythonConversion::ContextualWrapper(iter.first.ctx, *iter.first.base.second.get())); } else { PyErr_SetString(PyExc_StopIteration, "End of range reached"); - boost::python::throw_error_already_set(); - // Should be unreachable, but prevent control may reach end of - // non-void - throw std::runtime_error("unreachable"); + throw py::error_already_set(); } } - static void wrap(const char *python_name) + static void wrap(py::module &m, const char *python_name) { - class_>(python_name, no_init).def("__next__", next); + //FIXME + //py::class_>(m, python_name).def("__next__", next); } }; - static object get(wrapped_pair &x, int i) + static py::object get(wrapped_pair &x, int i) { if ((i >= 2) || (i < 0)) KeyError(); - return (i == 1) ? object(PythonConversion::ContextualWrapper(x.ctx, *x.base.second.get())) - : object(PythonConversion::string_converter().to_str(x.ctx, + return (i == 1) ? py::cast(PythonConversion::ContextualWrapper(x.ctx, *x.base.second.get())) + : py::cast(PythonConversion::string_converter().to_str(x.ctx, x.base.first)); } @@ -430,15 +418,15 @@ template struct map_pair_wrapper_uptr return PythonConversion::ContextualWrapper(t.ctx, *t.base.second.get()); } - static void wrap(const char *pair_name, const char *iter_name) + static void wrap(py::module &m, const char *pair_name, const char *iter_name) { - pair_iterator_wrapper::wrap(iter_name); - class_(pair_name, no_init) + pair_iterator_wrapper::wrap(m, iter_name); + py::class_(m, pair_name) .def("__iter__", iter) .def("__len__", len) .def("__getitem__", get) - .add_property("first", first_getter) - .add_property("second", second_getter); + .def_property_readonly("first", first_getter) + .def_property_readonly("second", second_getter); } }; @@ -487,24 +475,24 @@ template struct map_wrapper_uptr return x.base.count(k); } - static void wrap(const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) + static void wrap(py::module &m, const char *map_name, const char *kv_name, const char *kv_iter_name, const char *iter_name) { - map_pair_wrapper_uptr::wrap(kv_name, kv_iter_name); - typedef range_wrapper, PythonConversion::wrap_context> rw; - typename rw::iter_wrap().wrap(iter_name); - class_(map_name, no_init) + map_pair_wrapper_uptr::wrap(m, kv_name, kv_iter_name); + typedef range_wrapper> rw; + typename rw::iter_wrap().wrap(m, iter_name); + py::class_(m, map_name) .def("__iter__", rw::iter) .def("__len__", len) .def("__contains__", contains) .def("__getitem__", get) - .def("__setitem__", set, with_custodian_and_ward<1, 2>()); + .def("__setitem__", set, py::keep_alive<1, 2>()); } }; -#define WRAP_MAP(t, conv, name) \ - map_wrapper().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") -#define WRAP_MAP_UPTR(t, name) \ - map_wrapper_uptr().wrap(#name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") +#define WRAP_MAP(m, t, conv, name) \ + map_wrapper().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") +#define WRAP_MAP_UPTR(m, t, name) \ + map_wrapper_uptr().wrap(m, #name, #name "KeyValue", #name "KeyValueIter", #name "Iterator") NEXTPNR_NAMESPACE_END diff --git a/common/pywrappers.h b/common/pywrappers.h index d50af4c3..e55039c0 100644 --- a/common/pywrappers.h +++ b/common/pywrappers.h @@ -21,19 +21,13 @@ #ifndef PYWRAPPERS_H #define PYWRAPPERS_H -#include -#include -#include -#include -#include -#include -#include +#include #include #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN -using namespace boost::python; +namespace py = pybind11; namespace PythonConversion { template struct ContextualWrapper @@ -155,14 +149,14 @@ template struct fn_ using class_type = typename WrapIfNotContext::maybe_wrapped_t; using conv_result_type = typename rv_conv::ret_type; - static object wrapped_fn(class_type &cls) + static py::object wrapped_fn(class_type &cls) { Context *ctx = get_ctx(cls); Class &base = get_base(cls); try { - return object(rv_conv()(ctx, (base.*fn)())); + return py::cast(rv_conv()(ctx, (base.*fn)())); } catch (bad_wrap &) { - return object(); + return py::object(); } } @@ -176,14 +170,14 @@ template (cls); Class &base = get_base(cls); try { - return object(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1)))); + return py::cast(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1)))); } catch (bad_wrap &) { - return object(); + return py::object(); } } @@ -199,14 +193,14 @@ struct fn_wrapper_2a using conv_arg1_type = typename arg1_conv::arg_type; using conv_arg2_type = typename arg2_conv::arg_type; - static object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2) + static py::object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2) { Context *ctx = get_ctx(cls); Class &base = get_base(cls); try { - return object(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2)))); + return py::cast(rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2)))); } catch (bad_wrap &) { - return object(); + return py::object(); } } @@ -224,15 +218,15 @@ struct fn_wrapper_3a using conv_arg2_type = typename arg2_conv::arg_type; using conv_arg3_type = typename arg3_conv::arg_type; - static object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3) + static py::object wrapped_fn(class_type &cls, conv_arg1_type arg1, conv_arg2_type arg2, conv_arg3_type arg3) { Context *ctx = get_ctx(cls); Class &base = get_base(cls); try { - return object( + return py::cast( rv_conv()(ctx, (base.*fn)(arg1_conv()(ctx, arg1), arg2_conv()(ctx, arg2), arg3_conv()(ctx, arg3)))); } catch (bad_wrap &) { - return object(); + return py::object(); } } @@ -268,7 +262,7 @@ template struct f template static void def_wrap(WrapCls cls_, const char *name) { cls_.def(name, wrapped_fn); } - template static void def_wrap(WrapCls cls_, const char *name, Ta a = arg("arg1")) + template static void def_wrap(WrapCls cls_, const char *name, Ta a = py::arg("arg1")) { cls_.def(name, wrapped_fn, a); } @@ -413,20 +407,20 @@ template struct reado using class_type = typename WrapIfNotContext::maybe_wrapped_t; using conv_val_type = typename v_conv::ret_type; - static object wrapped_getter(class_type &cls) + static py::object wrapped_getter(class_type &cls) { Context *ctx = get_ctx(cls); Class &base = get_base(cls); try { - return object(v_conv()(ctx, (base.*mem))); + return py::cast(v_conv()(ctx, (base.*mem))); } catch (bad_wrap &) { - return object(); + return py::object(); } } template static void def_wrap(WrapCls cls_, const char *name) { - cls_.add_property(name, wrapped_getter); + cls_.def_property_readonly(name, wrapped_getter); } }; @@ -436,14 +430,14 @@ template ::maybe_wrapped_t; using conv_val_type = typename get_conv::ret_type; - static object wrapped_getter(class_type &cls) + static py::object wrapped_getter(class_type &cls) { Context *ctx = get_ctx(cls); Class &base = get_base(cls); try { - return object(get_conv()(ctx, (base.*mem))); + return py::cast(get_conv()(ctx, (base.*mem))); } catch (bad_wrap &) { - return object(); + return py::object(); } } @@ -458,7 +452,7 @@ template static void def_wrap(WrapCls cls_, const char *name) { - cls_.add_property(name, wrapped_getter, wrapped_setter); + cls_.def_property(name, wrapped_getter, wrapped_setter); } }; diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index 951745af..b8e48ccf 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -26,21 +26,19 @@ NEXTPNR_NAMESPACE_BEGIN -void arch_wrap_python() +void arch_wrap_python(py::module &m) { using namespace PythonConversion; - class_("ArchArgs").def_readwrite("type", &ArchArgs::type); + py::class_(m, "ArchArgs").def_readwrite("type", &ArchArgs::type); - class_("BelId").def_readwrite("index", &BelId::index); + py::class_(m, "BelId").def_readwrite("index", &BelId::index); - class_("WireId").def_readwrite("index", &WireId::index); + py::class_(m, "WireId").def_readwrite("index", &WireId::index); - class_("PipId").def_readwrite("index", &PipId::index); + py::class_(m, "PipId").def_readwrite("index", &PipId::index); - class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); - - auto arch_cls = class_, boost::noncopyable>("Arch", init()); - auto ctx_cls = class_, boost::noncopyable>("Context", no_init) + auto arch_cls = py::class_(m, "Arch").def(py::init()); + auto ctx_cls = py::class_(m, "Context") .def("checksum", &Context::checksum) .def("pack", &Context::pack) .def("place", &Context::place) @@ -54,21 +52,21 @@ void arch_wrap_python() typedef std::unordered_map AliasMap; typedef std::unordered_map HierarchyMap; - auto belpin_cls = class_>("BelPin", no_init); + auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); readonly_wrapper>::def_wrap(belpin_cls, "pin"); #include "arch_pybindings_shared.h" - WRAP_RANGE(Bel, conv_to_str); - WRAP_RANGE(Wire, conv_to_str); - WRAP_RANGE(AllPip, conv_to_str); - WRAP_RANGE(Pip, conv_to_str); - WRAP_RANGE(BelPin, wrap_context); + WRAP_RANGE(m, Bel, conv_to_str); + WRAP_RANGE(m, Wire, conv_to_str); + WRAP_RANGE(m, AllPip, conv_to_str); + WRAP_RANGE(m, Pip, conv_to_str); + WRAP_RANGE(m, BelPin, wrap_context); - WRAP_MAP_UPTR(CellMap, "IdCellMap"); - WRAP_MAP_UPTR(NetMap, "IdNetMap"); - WRAP_MAP(HierarchyMap, wrap_context, "HierarchyMap"); + WRAP_MAP_UPTR(m, CellMap, "IdCellMap"); + WRAP_MAP_UPTR(m, NetMap, "IdNetMap"); + WRAP_MAP(m, HierarchyMap, wrap_context, "HierarchyMap"); } NEXTPNR_NAMESPACE_END diff --git a/generic/arch_pybindings.cc b/generic/arch_pybindings.cc index 2600cac0..5c036ad0 100644 --- a/generic/arch_pybindings.cc +++ b/generic/arch_pybindings.cc @@ -35,13 +35,13 @@ template <> struct string_converter }; } // namespace PythonConversion -void arch_wrap_python() +void arch_wrap_python(py::module &m) { using namespace PythonConversion; - auto arch_cls = class_, boost::noncopyable>("Arch", init()); + auto arch_cls = py::class_(m, "Arch").def(py::init()); - auto dxy_cls = class_>("DecalXY_", no_init); + auto dxy_cls = py::class_>(m, "DecalXY_"); readwrite_wrapper, conv_from_str>::def_wrap(dxy_cls, "decal"); readwrite_wrapper, pass_through>::def_wrap( @@ -49,15 +49,15 @@ void arch_wrap_python() readwrite_wrapper, pass_through>::def_wrap( dxy_cls, "y"); - auto ctx_cls = class_, boost::noncopyable>("Context", no_init) + auto ctx_cls = py::class_(m, "Context") .def("checksum", &Context::checksum) .def("pack", &Context::pack) .def("place", &Context::place) .def("route", &Context::route); - class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); + py::class_(m, "BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); - class_("DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay); + py::class_(m, "DelayInfo").def("maxDelay", &DelayInfo::maxDelay).def("minDelay", &DelayInfo::minDelay); fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getBelType"); @@ -154,86 +154,86 @@ void arch_wrap_python() // Generic arch construction API fn_wrapper_4a_v, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addWire", - (arg("name"), "type", "x", + (py::arg("name"), "type", "x", "y")); fn_wrapper_6a_v, conv_from_str, conv_from_str, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addPip", - (arg("name"), "type", "srcWire", "dstWire", "delay", "loc")); + (py::arg("name"), "type", "srcWire", "dstWire", "delay", "loc")); fn_wrapper_5a_v, conv_from_str, conv_from_str, conv_from_str, pass_through>::def_wrap(ctx_cls, "addAlias", - (arg("name"), "type", "srcWire", "dstWire", "delay")); + (py::arg("name"), "type", "srcWire", "dstWire", "delay")); fn_wrapper_4a_v, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addBel", - (arg("name"), "type", + (py::arg("name"), "type", "loc", "gb")); fn_wrapper_3a_v, conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInput", - (arg("bel"), "name", "wire")); + (py::arg("bel"), "name", "wire")); fn_wrapper_3a_v, conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelOutput", - (arg("bel"), "name", "wire")); + (py::arg("bel"), "name", "wire")); fn_wrapper_3a_v, conv_from_str, conv_from_str>::def_wrap(ctx_cls, "addBelInout", - (arg("bel"), "name", "wire")); + (py::arg("bel"), "name", "wire")); fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupBel", (arg("group"), "bel")); + conv_from_str>::def_wrap(ctx_cls, "addGroupBel", (py::arg("group"), "bel")); fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupWire", (arg("group"), "wire")); + conv_from_str>::def_wrap(ctx_cls, "addGroupWire", (py::arg("group"), "wire")); fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupPip", (arg("group"), "pip")); + conv_from_str>::def_wrap(ctx_cls, "addGroupPip", (py::arg("group"), "pip")); fn_wrapper_2a_v, - conv_from_str>::def_wrap(ctx_cls, "addGroupGroup", (arg("group"), "grp")); + conv_from_str>::def_wrap(ctx_cls, "addGroupGroup", (py::arg("group"), "grp")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (arg("decal"), "graphic")); + pass_through>::def_wrap(ctx_cls, "addDecalGraphic", (py::arg("decal"), "graphic")); fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setWireDecal", (arg("wire"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setWireDecal", (py::arg("wire"), "decalxy")); fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setPipDecal", (arg("pip"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setPipDecal", (py::arg("pip"), "decalxy")); fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setBelDecal", (arg("bel"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setBelDecal", (py::arg("bel"), "decalxy")); fn_wrapper_2a_v, - unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", (arg("group"), "decalxy")); + unwrap_context>::def_wrap(ctx_cls, "setGroupDecal", (py::arg("group"), "decalxy")); fn_wrapper_3a_v, conv_from_str, pass_through>::def_wrap(ctx_cls, "setWireAttr", - (arg("wire"), "key", "value")); + (py::arg("wire"), "key", "value")); fn_wrapper_3a_v, conv_from_str, pass_through>::def_wrap(ctx_cls, "setBelAttr", - (arg("bel"), "key", "value")); + (py::arg("bel"), "key", "value")); fn_wrapper_3a_v, conv_from_str, pass_through>::def_wrap(ctx_cls, "setPipAttr", - (arg("pip"), "key", "value")); + (py::arg("pip"), "key", "value")); fn_wrapper_1a_v>::def_wrap( - ctx_cls, "setLutK", arg("K")); + ctx_cls, "setLutK", py::arg("K")); fn_wrapper_2a_v, - pass_through>::def_wrap(ctx_cls, "setDelayScaling", (arg("scale"), "offset")); + pass_through>::def_wrap(ctx_cls, "setDelayScaling", (py::arg("scale"), "offset")); fn_wrapper_2a_v, conv_from_str>::def_wrap(ctx_cls, "addCellTimingClock", - (arg("cell"), "port")); + (py::arg("cell"), "port")); fn_wrapper_4a_v, conv_from_str, conv_from_str, pass_through>::def_wrap(ctx_cls, "addCellTimingDelay", - (arg("cell"), "fromPort", "toPort", "delay")); + (py::arg("cell"), "fromPort", "toPort", "delay")); fn_wrapper_5a_v, conv_from_str, conv_from_str, pass_through, pass_through>::def_wrap(ctx_cls, "addCellTimingSetupHold", - (arg("cell"), "port", "clock", "setup", "hold")); + (py::arg("cell"), "port", "clock", "setup", "hold")); fn_wrapper_4a_v, conv_from_str, conv_from_str, pass_through>::def_wrap(ctx_cls, "addCellTimingClockToOut", - (arg("cell"), "port", "clock", "clktoq")); + (py::arg("cell"), "port", "clock", "clktoq")); - WRAP_MAP_UPTR(CellMap, "IdCellMap"); - WRAP_MAP_UPTR(NetMap, "IdNetMap"); - WRAP_MAP(HierarchyMap, wrap_context, "HierarchyMap"); - WRAP_VECTOR(const std::vector, conv_to_str); + WRAP_MAP_UPTR(m, CellMap, "IdCellMap"); + WRAP_MAP_UPTR(m, NetMap, "IdNetMap"); + WRAP_MAP(m, HierarchyMap, wrap_context, "HierarchyMap"); + WRAP_VECTOR(m, const std::vector, conv_to_str); } NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index 9dd17f01..9011d1dc 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -26,12 +26,12 @@ NEXTPNR_NAMESPACE_BEGIN -void arch_wrap_python() +void arch_wrap_python(py::module &m) { using namespace PythonConversion; - class_("ArchArgs").def_readwrite("type", &ArchArgs::type); + py::class_(m, "ArchArgs").def_readwrite("type", &ArchArgs::type); - enum_().type)>("iCE40Type") + py::enum_().type)>(m, "iCE40Type") .value("NONE", ArchArgs::NONE) .value("LP384", ArchArgs::LP384) .value("LP1K", ArchArgs::LP1K) @@ -47,16 +47,14 @@ void arch_wrap_python() .value("U4K", ArchArgs::U4K) .export_values(); - class_("BelId").def_readwrite("index", &BelId::index); + py::class_(m, "BelId").def_readwrite("index", &BelId::index); - class_("WireId").def_readwrite("index", &WireId::index); + py::class_(m, "WireId").def_readwrite("index", &WireId::index); - class_("PipId").def_readwrite("index", &PipId::index); + py::class_(m, "PipId").def_readwrite("index", &PipId::index); - class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); - - auto arch_cls = class_, boost::noncopyable>("Arch", init()); - auto ctx_cls = class_, boost::noncopyable>("Context", no_init) + auto arch_cls = py::class_(m, "Arch").def(py::init()); + auto ctx_cls = py::class_(m, "Context") .def("checksum", &Context::checksum) .def("pack", &Context::pack) .def("place", &Context::place) @@ -70,21 +68,21 @@ void arch_wrap_python() typedef std::unordered_map AliasMap; typedef std::unordered_map HierarchyMap; - auto belpin_cls = class_>("BelPin", no_init); + auto belpin_cls = py::class_>(m, "BelPin"); readonly_wrapper>::def_wrap(belpin_cls, "bel"); readonly_wrapper>::def_wrap(belpin_cls, "pin"); #include "arch_pybindings_shared.h" - WRAP_RANGE(Bel, conv_to_str); - WRAP_RANGE(Wire, conv_to_str); - WRAP_RANGE(AllPip, conv_to_str); - WRAP_RANGE(Pip, conv_to_str); - WRAP_RANGE(BelPin, wrap_context); + WRAP_RANGE(m, Bel, conv_to_str); + WRAP_RANGE(m, Wire, conv_to_str); + WRAP_RANGE(m, AllPip, conv_to_str); + WRAP_RANGE(m, Pip, conv_to_str); + WRAP_RANGE(m, BelPin, wrap_context); - WRAP_MAP_UPTR(CellMap, "IdCellMap"); - WRAP_MAP_UPTR(NetMap, "IdNetMap"); - WRAP_MAP(HierarchyMap, wrap_context, "HierarchyMap"); + WRAP_MAP_UPTR(m, CellMap, "IdCellMap"); + WRAP_MAP_UPTR(m, NetMap, "IdNetMap"); + WRAP_MAP(m, HierarchyMap, wrap_context, "HierarchyMap"); } NEXTPNR_NAMESPACE_END