将带有输出参数的C ++函数包装在javascript / node中使用

时间:2018-07-13 17:45:50

标签: javascript c++ swig

给出一个定义为var input = 'input1'; var output = ''; var result = mylib.test(input, output); console.log(output); 的函数。如何配置SWIG接口,以便获得输出值?

这就是我从js中调用它的方式:

int test(char* input, char** output) {
  *output = input;
  return 0;
}

我知道这是行不通的,因为在javascript中字符串是不可变的,而且在SWIG中创建的接口不会写回输出参数。

这是C ++代码:

width="309px;"

1 个答案:

答案 0 :(得分:1)

将显示的C ++语义映射到JavaScript的最简单方法是使SWIG使该函数的行为与使用真实JavaScript而不是C ++编写时的行为相同。也就是说,我们将使您的函数的行为类似于以下JavaScript伪代码:

function test(input) {
    if (error) {
        throw ....
    }
    return input;
}

要使用SWIG做到这一点,我们需要编写一些类型图。 (在某些情况下,those typemaps already exist对我们来说是标准SWIG库的一部分,但是对于char **来说,没有这样的类型映射,因为语义不太明显。)

我使您的代码可以与以下SWIG界面配合使用,如下所示:

%module test

// #1
%typemap(in,numinputs=0) char **output (char *tmp) {
    $1 = &tmp; // #2
}

// #3
%typemap(argout,fragment="SWIG_FromCharPtr") char **output {
    $result = SWIG_FromCharPtr(tmp$argnum);
    // Without more effort the following would be an illegal cast I think:
    //SWIG_AppendOutput($result, tmp$argnum);
}

// #4
%typemap(out) int test %{
    if ($1) {
        SWIG_exception_fail(SWIG_ERROR, "Well, that was unexpected");
    }
%}

%inline %{
int test(char *input, char **output) {
    *output = input;
    return 0;
}
%}

基本上,我们在这里做了4件事:

  1. 一种类型映射,它设置了**output参数,而根本没有从JavaScript接受输入。 numinputs=0抑制了从JavaScript被调用者接收参数的需要。
  2. 相反,我们只是在包装器内部使用局部变量作为输出
  3. 调用该函数后,请使用我们本地变量中的值作为该函数返回JavaScript的方法。我们需要将其称为tmp$argnum,因为SWIG在内部对局部变量进行了编号,以避免在typemap在intypemap上多次匹配时发生冲突,但是它不会在argout上自动进行匹配。 SWIG提供了一些标准宏来附加事物以返回多个项目,但是它们在这里无法解决问题,因为它最终会进行非法的转换,而且我还是不太喜欢使用这些语义。此处的片段确保我们对生成的代码中的字符串输出提供了一些预先编写的支持。
  4. 使用原始返回值执行某些操作,在这种情况下,如果我们从C ++得到非零值(即错误),则会抛出异常。还有其他处理方法,但是这是不只是默默忽略错误的最简单方法。

我以前几乎从未使用过SWIG的JavaScript支持,因此一旦完成basic documentation for building a module的工作,就足以运行以下测试:

var test = require("./build/Release/test");

console.log(test.test("blah blah"));

按预期工作。我还进行了快速测试,更改了返回值以强制执行异常,并且该异常的行为也符合预期。

免责声明:这样做使我对node / V8的了解几乎翻了一番,因此请仔细检查我的工作情况。