Embind用于将C ++和JavaScript交互



Embind is used to bind C++ functions and classes to JavaScript, so that the compiled code can be used in a natural way by “normal” JavaScript. Embind also supports calling JavaScript classes from C++.

Embind has support for binding most C++ constructs, including those introduced in C++11 and C++14. Its only significant limitation is that it does not currently support raw pointers with complicated lifetime semantics.

This article shows how to use EMSCRIPTEN_BINDINGS() blocks to create bindings for functions, classes, value types, pointers (including both raw and smart pointers), enums, and constants, and how to create bindings for abstract classes that can be overridden in JavaScript. It also briefly explains how to manage the memory of C++ object handles passed to JavaScript.


In addition to the code in this article:

  • There are many other examples of how to use Embind in the Test Suite.
  • Connecting C++ and JavaScript on the Web with Embind (slides from CppCon 2014) contains more examples and information about Embind’s design philosophy and implementation.


Embind was inspired by Boost.Python and uses a very similar approach for defining bindings.

A quick example

The following code uses an EMSCRIPTEN_BINDINGS() block to expose the simple C++ lerp() function() to JavaScript.

// quick_example.cpp
#include <emscripten/bind.h>

using namespace emscripten;

float lerp(float a, float b, float t) {
    return (1 - t) * a + t * b;

    function("lerp", &lerp);

To compile the above example using embind, we invoke emcc with the bind option:

emcc --bind -o quick_example.js quick_example.cpp

The resulting quick_example.js file can be loaded as a node module or via a <script> tag:

<!doctype html>
    var Module = {
      onRuntimeInitialized: function() {
        console.log('lerp result: ' + Module.lerp(1, 2, 0.5));
  <script src="quick_example.js"></script>


We use the onRuntimeInitialized callback to run code when the runtime is ready, which is an asynchronous operation (in order to compile WebAssembly).


Open the developer tools console to see the output of console.log.

The code in an EMSCRIPTEN_BINDINGS() block runs when the JavaScript file is initially loaded (at the same time as the global constructors). The function lerp()’s parameter types and return type are automatically inferred by embind.

All symbols exposed by embind are available on the Emscripten Module object.


Always access objects through the Module object object, as shown above.

While the objects are also available in the global namespace by default, there are cases where they will not be (for example, if you use the closure compiler to minify code or wrap compiled code in a function to avoid polluting the global namespace). You can of course use whatever name you like for the module by assigning it to a new variable: var MyModuleName = Module;.


Exposing classes to JavaScript requires a more complicated binding statement. For example:

class MyClass {
  MyClass(int x, std::string y)
    : x(x)
    , y(y)

  void incrementX() {

  int getX() const { return x; }
  void setX(int x_) { x = x_; }

  static std::string getStringFromInstance(const MyClass& instance) {
    return instance.y;

  int x;
  std::string y;

// Binding code
EMSCRIPTEN_BINDINGS(my_class_example) {
    .constructor<int, std::string>()
    .function("incrementX", &MyClass::incrementX)
    .property("x", &MyClass::getX, &MyClass::setX)
    .class_function("getStringFromInstance", &MyClass::getStringFromInstance)

The binding block defines a chain of member function calls on the temporary class_ object (this same style is used in Boost.Python). The functions register the class, its constructor(), member function()class_function() (static) and property().


This binding block binds the class and all its methods. As a rule you should bind only those items that are actually needed, as each binding increases the code size. For example, it would be rare to bind private or internal methods.

An instance of MyClass can then be created and used in JavaScript as shown below:

var instance = new Module.MyClass(10, "hello");
instance.x; // 11
instance.x = 20; // 20
Module.MyClass.getStringFromInstance(instance); // "hello"

Memory management

JavaScript, specifically ECMA-262 Edition 5.1, does not support finalizers or weak references with callbacks. Therefore there is no way for Emscripten to automatically call the destructors on C++ objects.


JavaScript code must explicitly delete any C++ object handles it has received, or the Emscripten heap will grow indefinitely.

var x = new Module.MyClass;

var y = Module.myFunctionThatReturnsClassInstance();

Value types

Manual memory management for basic types is onerous, so embind provides support for value types. Value arrays are converted to and from JavaScript Arrays and value objects are converted to and from JavaScript Objects.

Consider the example below:

struct Point2f {
    float x;
    float y;

struct PersonRecord {
    std::string name;
    int age;

PersonRecord findPersonAtLocation(Point2f);

EMSCRIPTEN_BINDINGS(my_value_example) {

        .field("name", &PersonRecord::name)
        .field("age", &PersonRecord::age)

    function("findPersonAtLocation", &findPersonAtLocation);

The JavaScript code does not need to worry about lifetime management.

var person = Module.findPersonAtLocation([10.2, 156.5]);
console.log('Found someone! Their name is ' + person.name + ' and they are ' + person.age + ' years old');

Advanced class concepts

Raw pointers

Because raw pointers have unclear lifetime semantics, embind requires their use to be marked with allow_raw_pointers.

For example:

class C {};
C* passThrough(C* ptr) { return ptr; }
    function("passThrough", &passThrough, allow_raw_pointers());


Currently the markup serves only to whitelist raw pointer use, and show that you’ve thought about the use of the raw pointers. Eventually we hope to implement Boost.Python-like raw pointer policies for managing object ownership.

External constructors

There are two ways to specify constructors for a class.

The zero-argument template form invokes the natural constructor with the arguments specified in the template. For example:

class MyClass {
  MyClass(int, float);
  void someFunction();

EMSCRIPTEN_BINDINGS(external_constructors) {
    .constructor<int, float>()
    .function("someFunction", &MyClass::someFunction)

The second form of the constructor takes a function pointer argument, and is used for classes that construct themselves using a factory function. For example:

class MyClass {
  virtual void someFunction() = 0;
MyClass* makeMyClass(int, float); //Factory function.

EMSCRIPTEN_BINDINGS(external_constructors) {
    .constructor(&makeMyClass, allow_raw_pointers())
    .function("someFunction", &MyClass::someFunction)

The two constructors present exactly the same interface for constructing the object in JavaScript. Continuing the example above:

var instance = new MyClass(10, 15.5);
// instance is backed by a raw pointer to a MyClass in the Emscripten heap

Smart pointers

To manage object lifetime with smart pointers, embind must be told about the smart pointer type.

For example, consider managing a class C’s lifetime with std::shared_ptr<C>. The best way to do this is to use smart_ptr_constructor() to register the smart pointer type:

EMSCRIPTEN_BINDINGS(better_smart_pointers) {
        .smart_ptr_constructor("C", &std::make_shared<C>)

When an object of this type is constructed (e.g. using new Module.C()) it returns a std::shared_ptr<C>.

An alternative is to use smart_ptr() in the EMSCRIPTEN_BINDINGS() block:

EMSCRIPTEN_BINDINGS(smart_pointers) {

Using this definition, functions can return std::shared_ptr<C> or take std::shared_ptr<C> as arguments, but new Module.C() would still return a raw pointer.


embind has built-in support for return values of type std::unique_ptr.

Custom smart pointers

To teach embind about custom smart pointer templates, you must specialize the smart_ptr_trait template.

Non-member-functions on the JavaScript prototype

Methods on the JavaScript class prototype can be non-member functions, as long as the instance handle can be converted to the first argument of the non-member function. The classic example is when the function exposed to JavaScript does not exactly match the behavior of a C++ method.

struct Array10 {
    int& get(size_t index) {
        return data[index];
    int data[10];

val Array10_get(Array10& arr, size_t index) {
    if (index < 10) {
        return val(arr.get(index));
    } else {
        return val::undefined();

EMSCRIPTEN_BINDINGS(non_member_functions) {
        .function("get", &Array10_get)

If JavaScript calls Array10.prototype.get with an invalid index, it will return undefined.

Deriving from C++ classes in JavaScript

If C++ classes have virtual or abstract member functions, it’s possible to override them in JavaScript. Because JavaScript has no knowledge of the C++ vtable, embind needs a bit of glue code to convert C++ virtual function calls into JavaScript calls.

Abstract methods

Let’s begin with a simple case: pure virtual functions that must be implemented in JavaScript.

struct Interface {
    virtual void invoke(const std::string& str) = 0;

struct InterfaceWrapper : public wrapper<Interface> {
    void invoke(const std::string& str) {
        return call<void>("invoke", str);

        .function("invoke", &Interface::invoke, pure_virtual())

allow_subclass() adds two special methods to the Interface binding: extend and implementextend allows JavaScript to subclass in the style exemplified by Backbone.js. implement is used when you have a JavaScript object, perhaps provided by the browser or some other library, and you want to use it to implement a C++ interface.


The pure_virtual annotation on the function binding allows JavaScript to throw a helpful error if the JavaScript class does not override invoke(). Otherwise, you may run into confusing errors.

extend example

var DerivedClass = Module.Interface.extend("Interface", {
    // __construct and __destruct are optional.  They are included
    // in this example for illustration purposes.
    // If you override __construct or __destruct, don't forget to
    // call the parent implementation!
    __construct: function() {
    __destruct: function() {
    invoke: function() {
        // your code goes here

var instance = new DerivedClass;

implement example

var x = {
    invoke: function(str) {
        console.log('invoking with: ' + str);
var interfaceObject = Module.Interface.implement(x);

Now interfaceObject can be passed to any function that takes an Interface pointer or reference.

Non-abstract virtual methods

If a C++ class has a non-pure virtual function, it can be overridden — but does not have to be. This requires a slightly different wrapper implementation:

struct Base {
    virtual void invoke(const std::string& str) {
        // default implementation

struct BaseWrapper : public wrapper<Base> {
    void invoke(const std::string& str) {
        return call<void>("invoke", str);

        .function("invoke", optional_override([](Base& self, const std::string& str) {
            return self.Base::invoke(str);

When implementing Base with a JavaScript object, overriding invoke is optional. The special lambda binding for invoke is necessary to avoid infinite mutual recursion between the wrapper and JavaScript.

Base classes

Base class bindings are defined as shown:

    class_<DerivedClass, base<BaseClass>>("DerivedClass");

Any member functions defined on BaseClass are then accessible to instances of DerivedClass. In addition, any function that accepts an instance of BaseClass can be given an instance of DerivedClass.

Automatic downcasting

If a C++ class is polymorphic (that is, it has a virtual method), then embind supports automatic downcasting of function return values.

class Base { virtual ~Base() {} }; // the virtual makes Base and Derived polymorphic
class Derived : public Base {};
Base* getDerivedInstance() {
    return new Derived;
EMSCRIPTEN_BINDINGS(automatic_downcasting) {
    class_<Derived, base<Base>>("Derived");
    function("getDerivedInstance", &getDerivedInstance, allow_raw_pointers());

Calling Module.getDerivedInstance from JavaScript will return a Derived instance handle from which all of Derived’s methods are available.


Embind must understand the fully-derived type for automatic downcasting to work.

Overloaded functions

Constructors and functions can be overloaded on the number of arguments, but embind does not support overloading based on type. When specifying an overload, use the select_overload() helper function to select the appropriate signature.

struct HasOverloadedMethods {
    void foo();
    void foo(int i);
    void foo(float f) const;

        .function("foo", select_overload<void()>(&HasOverloadedMethods::foo))
        .function("foo_int", select_overload<void(int)>(&HasOverloadedMethods::foo))
        .function("foo_float", select_overload<void(float)const>(&HasOverloadedMethods::foo))


Embind’s enumeration support works with both C++98 enums and C++11 “enum classes”.

enum OldStyle {

enum class NewStyle {

EMSCRIPTEN_BINDINGS(my_enum_example) {
        .value("ONE", OLD_STYLE_ONE)
        .value("TWO", OLD_STYLE_TWO)
        .value("ONE", NewStyle::ONE)
        .value("TWO", NewStyle::TWO)

In both cases, JavaScript accesses enumeration values as properties of the type.



To expose a C++ constant() to JavaScript, simply write:

EMSCRIPTEN_BINDINGS(my_constant_example) {

SOME_CONSTANT can have any type known to embind.

Memory views

In some cases it is valuable to expose raw binary data directly to JavaScript code as a typed array, allowing it to be used without copying. This is useful for instance for uploading large WebGL textures directly from the heap.

Memory views should be treated like raw pointers; lifetime and validity are not managed by the runtime and it’s easy to corrupt data if the underlying object is modified or deallocated.

#include <emscripten/bind.h>
#include <emscripten/val.h>

using namespace emscripten;

unsigned char *byteBuffer = /* ... */;
size_t bufferLength = /* ... */;

val getBytes() {
    return val(typed_memory_view(bufferLength, byteBuffer));

EMSCRIPTEN_BINDINGS(memory_view_example) {
    function("getBytes", &getBytes);

The calling JavaScript code will receive a typed array view into the emscripten heap:

var myUint8Array = Module.getBytes()
var xhr = new XMLHttpRequest();
xhr.open('POST', /* ... */);

The typed array view will be of the appropriate matching type, such as Uint8Array for an unsigned char array or pointer.

Using val to transliterate JavaScript to C++

Embind provides a C++ class, emscripten::val, which you can use to transliterate JavaScript code to C++. Using val you can call JavaScript objects from your C++, read and write their properties, or coerce them to C++ values like a boolint, or std::string.

The example below shows how you can use val to call the JavaScript Web Audio API from C++:


This example is based on the excellent Web Audio tutorial: Making sine, square, sawtooth and triangle waves (stuartmemo.com). There is an even simpler example in the emscripten::val documentation.

First consider the JavaScript below, which shows how to use the API:

// Get web audio api context
var AudioContext = window.AudioContext || window.webkitAudioContext;

// Got an AudioContext: Create context and OscillatorNode
var context = new AudioContext();
var oscillator = context.createOscillator();

// Configuring oscillator: set OscillatorNode type and frequency
oscillator.type = 'triangle';
oscillator.frequency.value = 261.63; // value in hertz - middle C

// Playing

// All done!

The code can be transliterated to C++ using val, as shown below:

#include <emscripten/val.h>
#include <stdio.h>
#include <math.h>

using namespace emscripten;

int main() {
  val AudioContext = val::global("AudioContext");
  if (!AudioContext.as<bool>()) {
    printf("No global AudioContext, trying webkitAudioContext\n");
    AudioContext = val::global("webkitAudioContext");

  printf("Got an AudioContext\n");
  val context = AudioContext.new_();
  val oscillator = context.call<val>("createOscillator");

  printf("Configuring oscillator\n");
  oscillator.set("type", val("triangle"));
  oscillator["frequency"].set("value", val(261.63)); // Middle C

  oscillator.call<void>("connect", context["destination"]);
  oscillator.call<void>("start", 0);

  printf("All done!\n");

First we use global() to get the symbol for the global AudioContext object (or webkitAudioContext if that does not exist). We then use new_() to create the context, and from this context we can create an oscillatorset() its properties (again using val) and then play the tone.

The example can be compiled on the Linux/macOS terminal with:

emcc -O2 -Wall -Werror --bind -o oscillator.html oscillator.cpp

Built-in type conversions

Out of the box, embind provides converters for many standard C++ types:

C++ type JavaScript type
void undefined
bool true or false
char Number
signed char Number
unsigned char Number
short Number
unsigned short Number
int Number
unsigned int Number
long Number
unsigned long Number
float Number
double Number
std::string ArrayBuffer, Uint8Array, Uint8ClampedArray, Int8Array, or String
std::wstring String (UTF-16 code units)
emscripten::val anything

For convenience, embind provides factory functions to register std::vector<T> (register_vector()) and std::map<K, V> (register_map()) types:


A full example is shown below:

#include <emscripten/bind.h>
#include <string>
#include <vector>

using namespace emscripten;

std::vector<int> returnVectorData () {
  std::vector<int> v(10, 1);
  return v;

std::map<int, std::string> returnMapData () {
  std::map<int, std::string> m;
  m.insert(std::pair<int, std::string>(10, "This is a string."));
  return m;

  function("returnVectorData", &returnVectorData);
  function("returnMapData", &returnMapData);

  // register bindings for std::vector<int> and std::map<int, std::string>.
  register_map<int, std::string>("map<int, string>");

The following JavaScript can be used to interact with the above C++.

var retVector = Module['returnVectorData']();

// vector size
var vectorSize = retVector.size();

// reset vector value
retVector.set(vectorSize - 1, 11);

// push value into vector

// retrieve value from the vector
for (var i = 0; i < retVector.size(); i++) {
    console.log("Vector Value: ", retVector.get(i));

// expand vector size
retVector.resize(20, 1);

var retMap = Module['returnMapData']();

// map size
var mapSize = retMap.size();

// retrieve value from map
console.log("Map Value: ", retMap.get(10));

// figure out which map keys are available
// NB! You must call `register_vector<key_type>`
// to make vectors available
var mapKeys = retMap.keys();
for (var i = 0; i < mapKeys.size(); i++) {
    var key = mapKeys.get(i);
    console.log("Map key/value: ", key, retMap.get(key));

// reset the value at the given index position
retMap.set(10, "OtherValue");


At time of writing there has been no comprehensive embind performance testing, either against standard benchmarks, or relative to WebIDL Binder.

The call overhead for simple functions has been measured at about 200 ns. While there is room for further optimisation, so far its performance in real-world applications has proved to be more than acceptable.

Next  Previous


编程学习 ·

使用ssh连接window和 oracle virtualBox中的虚拟机 保姆级教程

目录环境基本连接步骤进一步配置hostname环境虚拟机 VM Virtualbox 6.1 虚拟机系统 debain 10.3虚拟机网卡:1.虚拟机网卡2.主机 windows 10配置好以上环境后开始配置虚拟机,当然host-only网络适配器的ip地址可以自己设置。 基本连接步骤 第一步: 虚拟机中运行 ps -e | gr…
编程学习 ·


程序员——必备数学知识!!!Attention 本博客转发至百度aistudio的<深度学习7日入门-cv疫情检测>,课程非常棒!本人力推! 博客转发地址:https://aistudio.baidu.com/aistudio/projectdetail/604807 课程报名地址:https://aistudio.baidu.com/aistudio/education/group/i…
编程学习 ·


大O表示法(1)常见的大o数量级函数(2)其他算法复杂度表示法 基本操作数量函数T(n)的精确值并不是特别重要,重要的是Tn(n)中起决定性因素的主导部分。用动态的眼光看,就是当问题规模增大的时候,T(n)中的一些部分会盖过其他部分的贡献。 数量级函数描述了T(n)中随着n增加而…
编程学习 ·


diff -b 忽略空格 -B 忽略空行 -i 忽略大小写 -c 显示文件所有内容并标不同 -r 对比输出 -u 合并输出 patch patch 源文件 布丁文件 -b 备份原文件 cut 检测apache服务器被谁访问的次数最多,显示访问者ip并显示访问次数 cat /etc/httpd/logs/access_log | cut…
编程学习 ·


Java语言概述 Java语言是一款面向对象的高级语言,是由Sun Microsystems公司(现已被oracle公司收购)。由James Gosling和同事们共同研发,并在1995年正式推出,据oracle官方数据指数,目前全球已有上亿的系统是使用Java开发的。Java是一门面向对象编程语言,不仅吸收了C++语言…
编程学习 ·


首先,CSI摄像头和USB摄像头的调用方式是不一样的。 遇到过的错误 linano@jetson-nano$:python3 mpy-Copyl.py [ WARN:0 ] qlobal /home/nvidia/host/build opencv/nv opencv/modules/videoio/src/cap qstreamer. Cpp (1757) handleMessage OpenCV | GStreamer warninq: Embedd…
编程学习 ·


编程学习 ·


编程学习 ·


编程学习 ·

mvc:resources 配置不生效问题

编程学习 ·


题目:给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的、面积不为零的三角形的最大周长。如果不能形成任何面积不为零的三角形,返回 0。 #输出示例 输入:[2,1,2] 输出:5 输入:[1,5,1] 输出:0 输入:[3,2,3,4] 输出:10 输入:[3,6,2,3] 输出:8 #inclu…
编程学习 ·


一 查询模式 待定,日后补充 二 中断模式 1 中断接收 1.1中断接收流程 先在启动文件中找到中断向量表(此处以USART1为例子)然后找到USART1_IRQHandler的函数定义在这里就会发现又跳转到了 HAL_UART_IRQHandler(&huart1);,追进去为下图所示:在图中标记的前三步是读取寄存…
编程学习 ·


this对象是是在运行时基于函数的执行环境绑定的 var object = {name: "My Object",getName: function(){return this.name; } } let b = object.getName; console.log(object.getName()); // "My Object" console.log(b()); // undefined 在全局函数中,…
编程学习 ·


JAVA中集合的迭代/遍历方法以下讲解的遍历方式/迭代方式,是所有Collection通用的一种方式在Map集合中不能使用,在所有的Collection以及子类中使用第一步:创建迭代器对象: Iterator it = e.iterator();第二步:通过以上获取的迭代器对象开始迭代/遍历集合 以下两个方法为迭代…