美文网首页
Node引入C++库文件

Node引入C++库文件

作者: 汨罗在北方 | 来源:发表于2017-09-04 20:12 被阅读119次

    由于项目引入了一个通过C++语言实现的加密算法,需要在Node.js中调用相关端口实现加密,所以尝试实现了下载node.js中引入C++库文件。
    此项目中使用的引入方法是直接使用node-gym模块编译一个基于C++的node.js模块,然后在主程序中引入这个模块。

    node-gym

    node-gyp 是基于 GYP( 全称 Generate Your Projects,是谷歌开发的一套构建系统) 的。它会识别包或者项目中的 binding.gyp文件,这个里面是JSON的文件对工程依赖的各种文件进行了描述(可以理解为一个node版的CMakeList),然后根据该配置文件生成各系统下能进行编译的项目,如 Windows 下生成 Visual Studio 项目文件(*.sln 等),Unix 下生成 Makefile。在生成这些项目文件之后,node-gyp 还能调用各系统的编译工具(如 GCC)来将项目进行编译,得到最后的动态链接库 *.node 文件。

    cpp接口文件与gym编写

    插件通常都会暴漏某些对象和函数给 Node.js 中的 JavaScript 调用。当 JavaScript 调用函数时,也必须将将传入的参数映射给 C/C++ 代码,在函数调用完成后,还要映射 C/C++ 传回的返回值。
    下面代码演示了如何读取 JavaScript 传递来的函数以及如何传输返回值:
    C++文件如下:

    // AESencrypt.cpp
    #include <node.h>
    //此处引入要调用的头文件
    #include <aes_encrypt.h>
    namespace demo {
    
    using v8::Exception;
    using v8::FunctionCallbackInfo;
    using v8::Isolate;
    using v8::Local;
    using v8::Number;
    using v8::Object;
    using v8::String;
    using v8::Value;
    
    // 此处是encrypt方法的执行函数,在js中调用的参数通过args传入
    void Encrypt(const FunctionCallbackInfo<Value>& args) {
      Isolate* isolate = args.GetIsolate();
    
      // 检查参数个数
      if (args.Length() < 3) {
        // 如果个数不正确便扔回错误到JavaScript
        isolate->ThrowException(Exception::TypeError(
            String::NewFromUtf8(isolate, "Wrong number of arguments")));
        return;
      }
    
      // 检查参数类型
      if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
        isolate->ThrowException(Exception::TypeError(
            String::NewFromUtf8(isolate, "Wrong arguments")));
        return;
      }
    //当需要参数为string类型时的示例
         v8::String::Utf8Value param(args[2]->ToString());
         std::string inputstr= std::string(*param);
    
    char buffer[60];
      // 执行主函数
    aes_encrypt((char *)inputstr.c_str(),args[0],args[1],buffer);
    
      // 设定返回值 (using the passed in
      // FunctionCallbackInfo<Value>&)(返回一个字符串)
      args.GetReturnValue().Set(String::NewFromUtf8(isolate, buffer));
    }
    
    void Init(Local<Object> exports) {
      NODE_SET_METHOD(exports, "encrypt", Encrypt);
    }
    
    NODE_MODULE(AESencrypt, Init)
    
    }  // namespace demo
    

    值得注意的是,开发 Node.js 插件的开发时,必须输出一个初始化函数,模式如下:

    void Initialize(Local<Object> exports);
    NODE_MODULE(module_name, Initialize)
    

    在 NODE_MODULE 的行末没有分号,因为它并不是一次函数调用(详见 node.h)。module_name 必须二进制文件名相匹配(不包含文件名的 .node 后缀)。通过上述代码,我们在 AESencrypt.cpp 文件中声明了初始化函数是 Init,插件名称是 encrypt

    接下来编写gym文件

    {
         "targets": [
         {
             "target_name": "AESencrypt",
                 "sources": [ "AESencrypt.cpp" ],
                 "include_dirs": ["include"],
                 "libraries": [ "<(module_root_dir)/obj/lib/libencrypt.a" ],
                 "cflags!": [ "-fno-exceptions" ],
                 "cflags": [ "-std=c++11","-D_FILE_OFFSET_BITS=64"],
                 "cflags_cc!": [ "-fno-exceptions" ]
        }
      ]
    }
    

    其中libraries中引用库文件就好,其中一些关于跨系统的兼容可以参考官方文档

    接下来执行

    node-gyp configure  
    node-gyp build  
    

    编译文件生成一个.node文件

    在js代码中

    const AES = require('./build/Release/AESencrypt.node');
    

    引用,然后使用AES.encrypt()调用即可

    一些问题总结

    • 编译中引用静态库造成的问题
      由于编译生成的是动态库,引用的是静态库,在编译时可能弹出
    make: Entering directory '/home/work/work/testAES/build'
      ACTION Regenerating Makefile
      SOLINK_MODULE(target) Release/obj.target/testAES.node
    /usr/bin/ld: /home/work/work/testAES/obj/lib/libaes.a(test_aes.c.o): relocation R_X86_64_32S against `.rodata.cst16' can not be used when making a shared object; recompile with -fPIC
    /home/work/work/testAES/obj/lib/libaes.a: error adding symbols: Bad value
    collect2: error: ld returned 1 exit status
    

    报错。此时需要重新加"-fPic"参数编译一遍库文件。
    在cmake中需要写:

    set(CMAKE_POSITION_INDEPENDENT_CODE ON)
    
    • 自动生成
      由于最终需要提供给用户使用,模块在不同环境下都需要重新编译一遍,而每次部署都让用户执行一次node-gyp configure build明显不现实。直接在package.json里面加上一句
    gypfile": true
    

    让每次执行npm install的时候自动编译一遍,让问题能方便很多

    还可以考察的一些模块

    • node-ffi: 这个模块可以直接引入C++的库,实现不用操作任何C++代码的C++库文件引入
    • node-pre-gym:

    相关文章

      网友评论

          本文标题:Node引入C++库文件

          本文链接:https://www.haomeiwen.com/subject/uovejxtx.html