【问题标题】:Interaction with C++ classes in Emscripten与 Emscripten 中的 C++ 类交互
【发布时间】:2013-03-29 18:10:15
【问题描述】:

Emscripten 教程很好地解释了如何与 C 函数交互:https://github.com/kripken/emscripten/wiki/Interacting-with-code

但是你如何与 C++ 类交互:

  • 调用构造函数来创建对象
  • 删除一个对象
  • 防止类及其方法的死代码消除

【问题讨论】:

  • embind 应该会尽快解决这个问题。我想你可以看看github.com/kripken/emscripten/tree/master/tests/embind,但不确定它的最新情况。
  • 我在写完答案后看到了上面的评论。看起来现在有一些关于此事的文档here。有机会我会考虑使用embind
  • 简而言之,这很难,google for c++ name mangling。

标签: emscripten


【解决方案1】:

检查这个:http://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html

例子:

C++ 代码:

#include <emscripten/bind.h>

using namespace emscripten;

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

    void incrementX() {
        ++x;
    }

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

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

private:
    int x;
    std::string y;
};

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

JS代码:

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

【讨论】:

  • 太棒了 :) 谢谢一百万 :)
  • 不错的答案。谢谢。
【解决方案2】:

我这样做的方式是创建执行必要操作的“代理”函数。例如:

class HelloWorld
{
    int x;
  public:
    HelloWorld() { x = 0; }
    ~HelloWorld() {}
    void setX(int v) { x = v; }
    int getX() { return x; }
    // ...
};


//compile using "C" linkage to avoid name obfuscation
extern "C" {
  //constructor, returns a pointer to the HelloWorld object
  void *HW_constructor() {
    return new HelloWorld();
  }

  void HW_setX(HelloWorld *hw, int x) {
    hw->setX(x);
  }

  int HW_getX(HelloWorld *hw) {
    return hw->getX();
  }

  void HW_destructor(HelloWorld *hw) {
    delete hw;
  }
};

然后在 JS 中,您必须构建一个调用代理函数的对象的克隆(我知道这很烦人,但目前我不知道更好的解决方案):

// get references to the exposed proxy functions
var HW_constructor = Module.cwrap('HW_constructor', 'number', []);
var HW_destructor = Module.cwrap('HW_destructor', null, ['number']);
var HW_setX = Module.cwrap('HW_setX', null, ['number', 'number']);
var HW_getX = Module.cwrap('HW_getX', 'number', ['number']);

function HelloWorld() {
  this.ptr = HW_constructor();
}

HelloWorld.prototype.destroy = function () {
  HW_destructor(this.ptr);
};

HelloWorld.prototype.setX = function (x) {
  HW_setX(this.ptr, x);
};

HelloWorld.prototype.getX = function () {
  return HW_getX(this.ptr);
};

重要提示请记住,为了使其正常工作,您需要在 emcc 命令中添加以下标志,告诉它不要将代理方法作为死代码剥离(注意:这里的下划线是故意的并且很重要!):

emcc helloworld.cpp -o helloworld.js \
  -s EXPORTED_FUNCTIONS="['_HW_constructor','_HW_destructor','_HW_setX','_HW_getX']"

编辑:我创建了一个gist 供人们试用代码。

【讨论】:

  • 谢谢 - 干得好 .. 但我希望有一个更优雅的解决方案 ;-)
  • 是的,这里也一样哈哈。如果你找到一个,请告诉我! :)
猜你喜欢
  • 2016-05-15
  • 2011-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-09
  • 2012-02-19
  • 1970-01-01
相关资源
最近更新 更多