Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

给Node.js编译C++扩展 #7

Open
chemdemo opened this issue May 17, 2014 · 0 comments
Open

给Node.js编译C++扩展 #7

chemdemo opened this issue May 17, 2014 · 0 comments

Comments

@chemdemo
Copy link
Owner

前些日子在开发一个Node.js项目的时候,请求量什么的需要上报公司统一的monitor。已有的接口是C++写成的,也有编译好的二进制文件可以直接用shell命令调用,如果简单使用的话可能只需调用nodejschild_process模块执行命令行即可,但是感觉这种方法比较蹩脚,每一个前端请求都需要创建一个子进程,开销太大。于是决定使用C++库编译node扩展。

编译node扩展,本来官方文档说的已经很清晰了,按照文档一步步来即可,这里大概记录下编译过程和所碰到的问题。

1.新建attrlib.cc C++原文件,添加V8头文件、引入lib头文件:

#include <node.h>
#include <v8.h>
#include "Attr_API.h"
using namespace v8;

2.封装接口,完成对C++ lib api所需参数的类型、个数什么的做检查,对暴露的js接口进行容错,这里因之前完全没接触过C++,对它的各种数据类型的检查和转换花了不少的时间。

针对Attr_API.h头文件里的api接口(这里做为例子,其他接口省去了):

int adv_attr_set(int attr_id , size_t len , char* pvalue);

具体的封装:

Handle<Value> AdvAttrSet(const Arguments& args) {
    HandleScope scope;

    if(args.Length() < 3) {
        ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
        return scope.Close(Undefined());
    }

    v8::String::Utf8Value pVal(args[2]->ToString());

    Local<Integer> iRet = Integer::New(adv_attr_set(
        args[0]->Int32Value(),
        args[1]->IntegerValue(),
        (char*) *pVal
    ));

    return scope.Close(iRet);
}

3.暴露js接口:

void init(Handle<Object> exports) {
    exports->Set(String::NewSymbol("advAttrSet"),
        FunctionTemplate::New(AdvAttrSet)->GetFunction());
}

NODE_MODULE(AttrLib, init);

接下来编写binding.gyp,它就是一个json格式的配置文件(node低版本使用wscript文件进行编译,高版本都采用binding.gyp),接着使用node-gyp模块进行自动编译。

{
    "targets": [
        {
            "target_name": "AttrLib",
            "sources": [ "attrlib.cc" ],
            "libraries": [ "/data/nodejs/modules/base/tools/attrapi/attrapi.a" ]
        }
    ]
}

这里简单说下,如果C++ lib使用了静态(.a文件)或者动态链接库(.so文件),只需要在libraries这一项里指出该库的路劲即可,笔者一开始因为没引入静态链接库,编译出来的.node文件在调用的时候会报错:node: symbol lookup error: /data/nodejs/modules/base/test/attr_api/build/Release/attr_api.node: undefined symbol: Attr_API。

接下来又开始编译,再一次报错:6_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC /data/nodejs/modules/base/tools/attrapi/attrapi.a: could not read symbols: Bad value collect2: ld returned 1 exit status

问了google才知道是个很常见的C++编译错误,即需要指定-fPIC参数。但是看了binding.gyp似乎没这个配置,于是请教后台同学,恰好有人碰到过这个错误,发现是静态链接库不完整导致。

接下来开始编译,cd到binding.gyp所在路径,运行:node-gyp configure build,会生成一个build文件夹,进去之后会发现很多的文件,其中就有大家熟悉的Makefile,猜想node-gyp应该是通过配置生成Makefile,然后再运行make。

最后就是编写测试用例,逐个去跑了。

总体来说,编译node C++扩展扩展很简单,但是碰到抛异常的话,对于jser来说还是很蛋疼。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant