Git Product home page Git Product logo

v8pp's Introduction

Build Status

v8pp

Header-only library to expose C++ classes and functions into V8 to use them in JavaScript code. v8pp uses heavy template metaprogramming and variadic template parameters which requires modern compiler with C++11 support. The library has been tested on:

  • Microsoft Visual C++ 2013 (Windows 7/8)
  • GCC 4.8.1 (Ubuntu 13.10 with Linux kernel 3.11.0)
  • Clang 3.5 (Mac OS X 10.2)

Binding example

v8pp supports V8 versions after 3.21 with v8::Isolate usage in API. There are 2 targets for binding:

  • v8pp::module, a wrapper class around v8::ObjectTemplate
  • v8pp::class_, a template class wrapper around v8::FunctionTemplate

Both of them require a pointer to v8::Isolate instance. They allows to bind from C++ code such items as variables, functions, constants with a function set(name, item):

v8::Isolate* isolate;

int var;
int get_var() { return var + 1; }
void set_var(int x) { var = x + 1; }

struct X
{
	X(int v, bool u) : var(v) {}
	int var;
	int get() const { return var; }
	voi set(int x) { var = x; } 
};

// bind free variables and functions
v8pp::module mylib(isolate);
mylib
    // set read-only attribute
    .set_const("PI", 3.1415)
	// set variable available in JavaScript with name `var`
	.set("var", var)
	// set function get_var as `fun`
	.set("fun", &get_var)
	// set property `prop` with getter get_var() and setter set_var()
    .set("prop", property(get_var, set_var))

// bind class
v8pp::class_<X> X_class(isolate);
X_class
	// specify X constructor signature
	.ctor<int, bool>()
	// bind variable
	.set("var", &X::var)
	// bind function
	.set("fun", &X::set)
	// bind read-only property
    .set("prop", property(&X::get))

// set class into the module template
mylib.set("X", X_class);

// set bindings in global object as `mylib`
isolate->GetCurrentContext()->Global()->Set(
	v8::String::NewFromUtf8(isolate, "mylib"), mylib.new_instance());

After that bindings will be available in JavaScript:

mylib.var = mylib.PI + mylib.fun();
var x = new mylib.X(1, true);
mylib.prop = x.prop +x.fun();

Node.js and io.js addons

The library is suitable to make Node.js and io.js addons. See addons document.

void RegisterModule(v8::Handle<v8::Object> exports)
{
	v8pp::module addon(v8::Isolate::GetCurrent());

	// set bindings... 
	addon
		.set("fun", &function)
		.set("cls", my_class)
		;

	// set bindings as exports object prototype
	exports->SetPrototype(addon.new_instance());
}

v8pp also provides

  • v8pp - a static library to add several global functions (load/require to the v8 JavaScript context. require() is a system for loading plugins from shared libraries.
  • test - A binary for running JavaScript files in a context which has v8pp module loading functions provided.

v8pp module example

#include <iostream>

#include <v8pp/module.hpp>

namespace console {

void log(v8::FunctionCallbackInfo<v8::Value> const& args)
{
	v8::HandleScope handle_scope(args.GetIsolate());

	for (int i = 0; i < args.Length(); ++i)
	{
		if (i > 0) std::cout << ' ';
		v8::String::Utf8Value str(args[i]);
		std::cout <<  *str;
	}
	std::cout << std::endl;
}

v8::Handle<v8::Value> init(v8::Isolate* isolate)
{
	v8pp::module m(isolate);
	m.set("log", &log);
	return m.new_instance();
}

} // namespace console

Turning a v8pp module into a v8pp plugin

V8PP_PLUGIN_INIT(v8::Isolate* isolate)
{
	return console::init(isolate);
}

v8pp class binding example

#include <v8pp/module.hpp>
#include <v8pp/class.hpp>

#include <fstream>

namespace file {

bool rename(char const* src, char const* dest)
{
	return std::rename(src, dest) == 0;
}

class file_base
{
public:
	bool is_open() const { return stream_.is_open(); }
	bool good() const { return stream_.good(); }
	bool eof() const { return stream_.eof(); }
	void close() { stream_.close(); }

protected:
	std::fstream stream_;
};

class file_writer : public file_base
{
public:
	explicit file_writer(v8::FunctionCallbackInfo<v8::Value> const& args)
	{
		if (args.Length() == 1)
		{
			v8::String::Utf8Value str(args[0]);
			open(*str);
		}
	}

	bool open(char const* path)
	{
		stream_.open(path, std::ios_base::out);
		return stream_.good();
	}

	void print(v8::FunctionCallbackInfo<v8::Value> const& args)
	{
		v8::HandleScope scope(args.GetIsolate());

		for (int i = 0; i < args.Length(); ++i)
		{
			if (i > 0) stream_ << ' ';
			v8::String::Utf8Value str(args[i]);
			stream_ << *str;
		}
	}

	void println(v8::FunctionCallbackInfo<v8::Value> const& args)
	{
		print(args);
		stream_ << std::endl;
	}
};

class file_reader : public file_base
{
public:
	explicit file_reader(char const* path)
	{
		open(path);
	}

	bool open(const char* path)
	{
		stream_.open(path, std::ios_base::in);
		return stream_.good();
	}

	v8::Handle<v8::Value> getline(v8::Isolate* isolate)
	{
		if ( stream_.good() && ! stream_.eof())
		{
			std::string line;
			std::getline(stream_, line);
			return v8pp::to_v8(isolate, line);
		}
		else
		{
			return v8::Undefined(isolate);
		}
	}
};

v8::Handle<v8::Value> init(v8::Isolate* isolate)
{
	v8::EscapableHandleScope scope(isolate);

	// file_base binding, no .ctor() specified, object creation disallowed in JavaScript
	v8pp::class_<file_base> file_base_class(isolate);
	file_base_class
		.set("close", &file_base::close)
		.set("good", &file_base::good)
		.set("is_open", &file_base::is_open)
		.set("eof", &file_base::eof)
		;

	// .ctor<> template arguments declares types of file_writer constructor
	// file_writer inherits from file_base_class
	v8pp::class_<file_writer> file_writer_class(isolate);
	file_writer_class
		.ctor<v8::FunctionCallbackInfo<v8::Value> const&>()
		.inherit<file_base>()
		.set("open", &file_writer::open)
		.set("print", &file_writer::print)
		.set("println", &file_writer::println)
		;

	// .ctor<> template arguments declares types of file_reader constructor.
	// file_base inherits from file_base_class
	v8pp::class_<file_reader> file_reader_class(isolate);
	file_reader_class
		.ctor<char const*>()
		.inherit<file_base>()
		.set("open", &file_reader::open)
		.set("getln", &file_reader::getline)
		;

	// Create a module to add classes and functions to and return a
	// new instance of the module to be embedded into the v8 context
	v8pp::module m(isolate);
	m.set("rename", &rename)
	 .set("writer", file_writer_class)
	 .set("reader", file_reader_class)
		;

	return scope.Escape(m.new_instance());
}

} // namespace file

V8PP_PLUGIN_INIT(v8::Isolate* isolate)
{
	return file::init(isolate);
}

Creating a v8 context capable of using require() function

#include <v8pp/context.hpp>

v8pp::context context;
context.set_lib_path("path/to/plugins/lib");
// script can now use require() function. An application
// that uses v8pp::context must link against v8pp library.
v8::HandleScope scope(context.isolate());
context.run_file("some_file.js");

Using require() from JavaScript

// Load the file module from the class binding example and the
// console module.
var file    = require('file'),
    console = require('console')

var writer = new file.writer("file")
if (writer.is_open()) {
    writer.println("some text")
    writer.close()
    if (! file.rename("file", "newfile"))
        console.log("could not rename file")
}
else console.log("could not open `file'")

console.log("exit")

Create a handle to an externally referenced C++ class.

// Memory for C++ class will remain when JavaScript object is deleted.
// v8pp::no_factory avoids creating any constructor for your C++ class from
// JavaScript, useful for classes you only wish to inject.
typedef v8pp::class_<my_class> my_class_wrapper(isolate);
v8::Handle<v8::Value> val = my_class_wrapper::reference_external(&my_class::instance());
// Assuming my_class::instance() returns reference to class

Import externally created C++ class into v8pp.

// Memory for c++ object will be reclaimed by JavaScript using "delete" when
// JavaScript class is deleted.
typedef v8pp::class_<my_class> my_class_wrapper(isolate);
v8::Handle<v8::Value> val = my_class_wrapper::import_external(new my_class);

Compile-time configuration

The library uses several preprocessor macros, defined in v8pp/config.hpp file:

  • V8PP_ISOLATE_DATA_SLOT - A v8::Isolate data slot number, used to store v8pp internal data
  • V8PP_PLUGIN_INIT_PROC_NAME - Plugin initialization procedure name that should be exported from a v8pp plugin.
  • V8PP_PLUGIN_SUFFIX - Plugin filename suffix that would be added if the plugin name used in require() doesn't end with it.

v8pp alternatives

v8pp's People

Contributors

pmed avatar ottumm avatar

Watchers

wyrover avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.