用输出参数包装c ++函数以在javascript / node中使用

Wrap a c++ function with output parameter for use in javascript/node

给定一个定义为int test(char* input, char** output);的函数。如何配置swig接口以获得输出值?

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

1
2
3
4
var input = 'input1';
var output = '';
var result = mylib.test(input, output);
console.log(output);

我理解这不起作用,因为字符串在javascript中是不可变的,加上在swig中创建的接口不会写回输出参数。

下面是C++代码:

1
2
3
4
int test(char* input, char** output) {
  *output = input;
  return 0;
}


将你所显示的C++语义映射到JavaScript最简单的方法是让SWIG使函数像在实际JavaScript而不是C++中那样运行。也就是说,我们将使您的函数的行为类似于以下JavaScript伪代码:

1
2
3
4
5
6
function test(input) {
    if (error) {
        throw ....
    }
    return input;
}

要用swig实现这一点,我们需要编写一些类型图。(在某些情况下,这些类型映射已经作为标准swig库的一部分存在,但是对于char **,没有这样的类型映射,因为语义不太明显)。

我让您的代码使用以下swig接口,注释如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%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件事:

  • 一种类型映射,它设置**output参数,而根本不接受javascript的输入。numinputs=0抑制了从javascript调用方接收参数的需要。
  • 相反,我们使用一个局部变量作为包装器内部的输出
  • 调用函数后,使用本地变量中的值作为返回到javascript的函数。我们需要将其称为tmp$argnum,因为swig对局部变量进行了内部编号,以避免在类型映射中多次匹配类型映射时发生冲突,但不会在argout上自动执行此操作。Swig提供了一些标准宏,用于附加内容以返回多个项目,但它们在这里不适用,因为它最终执行了非法的强制转换,而且我也不太喜欢使用这些语义。这里的片段确保我们在生成的代码中对字符串输出有一些预先编写的支持。
  • 用原始返回值做一些事情,在这个例子中,如果我们从C++中得到非零(即错误),则抛出异常。还有其他方法可以处理这个问题,但这是最简单的方法,不只是默默地忽略错误。
  • 我以前几乎从未使用过Swig的Javascript支持,所以一旦我完成了构建模块的基本文档,这就足够我运行以下测试了:

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

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

    工作正常。我还做了一个快速的测试,改变返回值以强制执行异常,它的行为也和预期的一样。

    免责声明:这样做几乎增加了我对node/v8的曝光,所以请仔细检查我的工作。