09.17.08 - 11:50am
A couple of years ago I started and then abandoned a project that implemented what I thought then were a couple of cute ideas to do with using boost (the outstanding C++ libraries found at boost.org) to automatically generate wrappers for C++ objects to be used in Spidermonkey. I’ve shared pieces of the code before, to people who needed a C++-style error-reporter for Spidermonkey, or whatever, but I’ve never bothered actually sharing the whole thing. Well, that seems silly, so I’m sharing it now.
There is a lot left to be done here; as I said, I abandoned the project. All I’ve done since then is a tweak here or there, and a couple of cleanups I made today.
As I said, though, it implements some cute ideas:
- You can get a simple JS program running in two or three lines of C++ code (snipped from demo.cpp):
jswrap::jswrap_ptr js = jswrap::jswrap_ptr(new jswrap());
jsval rval;
js->runfile("test.js", &rval);
- Wrapping member function calls is a matter of one line of code, and can happen right inside your JSFunctionSpec array (this example is taken from pgsqljs.cpp):
{ "status", cmember0<PGconn_wrap, int,
&PGconn_wrap::status>().call,
0, DEF_PROP_FLAGS, 0 },
{ "transaction_status", cmember0<PGconn_wrap, int,
&PGconn_wrap::transaction_status>().call,
0, DEF_PROP_FLAGS, 0 },
{ "parameter_status", cmember1<PGconn_wrap, const char *, const char *,
&PGconn_wrap::parameter_status>().call,
1, DEF_PROP_FLAGS, 0 },
Essentially, I am creating template-classes (I couldn’t figure out how to make this magic work with template-functions — help wanted!) for each member function. The instantiated template class has one static function which knows how to marshall parameters and return values. I also handles exceptions by propagating JS-exceptions as C++-exceptions, and vice versa. This is a little hairy, but I think is an interesting approach. It means no IDL and no external help (other than some rather egregious abuse of the C pre-processor, thanks largely to help from Boost.Preprocessor). It also means you don’t have to maintain a separate call-through layer by hand. Better still, this actually works for C++ member-functions of C++ objects, not only static member functions, so foo.bar() in C++ is still foo.bar() in JS.
- It includes a sample embedding of the C PostgreSQL API, encapsulated in a C++ class.
- It handles rooting for you (or at least, I think it does, I haven’t tested very carefully).
- It provides an error-reporter and a stack-dumping facility, written in C++; both of which can be handy for debugging, or just as “recipes” for external projects. Steal at will.
- It’s amazingly terse, compared to the usual process for embedding spidermonkey. I’d love to see it get even moreso, while retaining flexibility.
It needs some cleanup and extension. It could also benefit from some additional love in the template department. I’d really like the member function spec lines to look like this, instead:
{ "status", wrappedfunc<&PGconn_wrap::status>, 0, DEF_PROP_FLAGS, 0 },
{ "transaction_status", wrappedfunc<&PGconn_wrap::transaction_status>, 0, DEF_PROP_FLAGS, 0 },
{ "parameter_status", wrappedfunc<&PGconn_wrap::parameter_status>(), 1, DEF_PROP_FLAGS, 0 },
I’d really like to have a better story for properties (ie., data-members) of C++ objects.
I’d really like to have an autoconf-based build environment that works with Mozilla-build (+boost?).
I wrote a boost::asio wrapper. It isn’t included here, but it would be neat to get it back on its feet and wrapped a little more cleanly than I had it before.
It needs more testing and feedback (which is why I am releasing it.)
Here it is. I’m pretty sure you’ll need Boost 1.35 (at a minimum) to build it, and you’ll have to tweak the Jamfile and some other spots to suit your own directory structure (look for the string “crowder”) and file/library locations. Feedback and patches are welcome and appreciated.
Category: JavaScript, software | | 4 Comments »