/*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2017 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
*/
#include <Python.h>
#include <iostream>
#include <list>
#include <string>
+#include <vector>
+#include "base/compiler.hh"
#include "base/cprintf.hh"
-#include "base/misc.hh"
+#include "base/logging.hh"
#include "base/types.hh"
#include "config/have_protobuf.hh"
+#include "python/pybind11/pybind.hh"
#include "sim/async.hh"
#include "sim/core.hh"
#endif
using namespace std;
+namespace py = pybind11;
// The python library is totally messed up with respect to constness,
// so make a simple macro to make life a little easier
}
/*
- * Load and initialize all of the python parts of M5, including Swig
- * and the embedded module importer.
+ * Load and initialize all of the python parts of M5.
*/
int
EmbeddedPython::initAll()
return 0;
}
-EmbeddedSwig::EmbeddedSwig(void (*init_func)(), const string& _context)
- : initFunc(init_func), context(_context)
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+ void (*init_func)(py::module &),
+ const char *_base)
+ : initFunc(init_func), registered(false), name(_name), base(_base)
{
- getList().push_back(this);
+ getMap()[_name] = this;
}
-list<EmbeddedSwig *> &
-EmbeddedSwig::getList()
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+ void (*init_func)(py::module &))
+ : initFunc(init_func), registered(false), name(_name), base("")
{
- static list<EmbeddedSwig *> the_list;
- return the_list;
+ getMap()[_name] = this;
}
void
-EmbeddedSwig::initAll()
+EmbeddedPyBind::init(py::module &m)
{
- char* old_context = _Py_PackageContext;
- // initialize SWIG modules. initFunc() is autogenerated and calls
- // all of the individual swig initialization functions.
- for (auto i : getList()) {
- // to ensure that the loaded modules are placed in the right
- // package we have to be a bit unorthodox and directly
- // manipulate the package context since swig simply calls
- // Py_InitModule with nothing but the module name of the
- // wrapper
- char* cstr = new char[i->context.size() + 1];
- strcpy(cstr, i->context.c_str());
- _Py_PackageContext = cstr;
- i->initFunc();
- delete[] cstr;
+ if (!registered) {
+ initFunc(m);
+ registered = true;
+ } else {
+ cprintf("Warning: %s already registered.\n", name);
}
- _Py_PackageContext = old_context;
}
-int
-initM5Python()
+bool
+EmbeddedPyBind::depsReady() const
+{
+ return base.empty() || getMap()[base]->registered;
+}
+
+std::map<std::string, EmbeddedPyBind *> &
+EmbeddedPyBind::getMap()
+{
+ static std::map<std::string, EmbeddedPyBind *> objs;
+ return objs;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyObject *
+#else
+void
+#endif
+EmbeddedPyBind::initAll()
+{
+ std::list<EmbeddedPyBind *> pending;
+
+ py::module m_m5 = py::module("_m5");
+ m_m5.attr("__package__") = py::cast("_m5");
+
+ pybind_init_core(m_m5);
+ pybind_init_debug(m_m5);
+
+ pybind_init_event(m_m5);
+ pybind_init_stats(m_m5);
+
+ for (auto &kv : getMap()) {
+ auto &obj = kv.second;
+ if (obj->base.empty()) {
+ obj->init(m_m5);
+ } else {
+ pending.push_back(obj);
+ }
+ }
+
+ while (!pending.empty()) {
+ for (auto it = pending.begin(); it != pending.end(); ) {
+ EmbeddedPyBind &obj = **it;
+ if (obj.depsReady()) {
+ obj.init(m_m5);
+ it = pending.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+
+#if PY_MAJOR_VERSION >= 3
+ return m_m5.ptr();
+#endif
+}
+
+void
+registerNativeModules()
{
- EmbeddedSwig::initAll();
- return EmbeddedPython::initAll();
+ auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll);
+ if (result == -1)
+ panic("Failed to add _m5 to Python's inittab\n");
}
/*
* Make the commands array weak so that they can be overridden (used
* by unit tests to specify a different python main function.
*/
-const char * __attribute__((weak)) m5MainCommands[] = {
+M5_WEAK const char *m5MainCommands[] = {
"import m5",
"m5.main()",
0 // sentinel is required
* main function.
*/
int
-m5Main(int argc, char **argv)
+m5Main(int argc, char **_argv)
{
#if HAVE_PROTOBUF
// Verify that the version of the protobuf library that we linked
GOOGLE_PROTOBUF_VERIFY_VERSION;
#endif
+
+#if PY_MAJOR_VERSION >= 3
+ typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
+ std::vector<WArgUPtr> v_argv;
+ std::vector<wchar_t *> vp_argv;
+ v_argv.reserve(argc);
+ vp_argv.reserve(argc);
+ for (int i = 0; i < argc; i++) {
+ v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
+ vp_argv.emplace_back(v_argv.back().get());
+ }
+
+ wchar_t **argv = vp_argv.data();
+#else
+ char **argv = _argv;
+#endif
+
PySys_SetArgv(argc, argv);
// We have to set things up in the special __main__ module
return 0;
}
-
-PyMODINIT_FUNC
-initm5(void)
-{
- initM5Python();
- PyImport_ImportModule(PyCC("m5"));
-}