编写node.js扩展C++插件模块

最近有个项目,需要用nodejs完成一个Long整型的算法,但是javascript本身不支持Long整型,整数范围为政府2的31次方,显然无法满足我们项目的需求,所以我最终想到了通过编写C++扩展模块来实现这部分算法,nodejs调用该模块来获取最终的返回值
我创建的npm包为swcUtil

安装node-gyp

1
sudo npm install node-gyp -g

node-gyp是一个跨平台的命令行工具,专门用来编译nodejs扩展插件,一下是安装node-gyp所需要的安装环境
You will also need to install:

  1. On Unix:
    • python (v2.7 recommended, v3.x.x is not supported)
    • make
    • A proper C/C++ compiler toolchain, like GCC
  2. On Mac OS X:
    • python (v2.7 recommended, v3.x.x is not supported) (already installed on Mac OS X)
      Xcode
    • You also need to install the Command Line Tools via Xcode. You can find this under the menu Xcode -> Preferences -> Downloads
      This step will install gcc and the related toolchain containing make
  3. On Windows:

    • Visual C++ Build Environment:
      Option 1: Install Visual C++ Build Tools using the Default Install option.
      Option 2: Install Visual Studio 2015 (or modify an existing installation) and select Common Tools for Visual C++ during setup. This also works with the free Community and Express for Desktop editions.
      [Windows Vista / 7 only] requires .NET Framework 4.5.1
    • Install Python 2.7 (v3.x.x is not supported), and run npm config set python python2.7 (or see below for further instructions on specifying the proper Python version and path.)
    • Launch cmd, npm config set msvs_version 2015
      If the above steps didn’t work for you, please visit Microsoft’s Node.js Guidelines for Windows for additional tips.
      If you have multiple Python versions installed, you can identify which Python version node-gyp uses by setting the ‘–python’ variable:

      1
      $ node-gyp --python /path/to/python2.7

      If node-gyp is called by way of npm and you have multiple versions of Python installed, then you can set npm’s ‘python’ config key to the appropriate value:

      1
      $ npm config set python /path/to/executable/python2.7

      Note that OS X is just a flavour of Unix and so needs python, make, and C/C++. An easy way to obtain these is to install XCode from Apple, and then use it to install the command line tools (under Preferences -> Downloads).

创建NPM目录

1
2
3
mkdir swcUtil
cd swcUtil
npm init

一路回车下去,最终会生成一个package.json文件,修改如下

{
  "name": "function_arguments",
  "version": "0.0.0",
  "description": "Node.js Addons Example #2",
  "main": "hash.js",
  "private": true,
  "dependencies": {
    "bindings": "~1.2.1",
    "nan": "~1.3.0"
  },
  "scripts": {
    "test": "node hash.js"
  },
  "gypfile": true
}

scripts中的test是为了方便待会测试模块是否能调用成功
hash.js为入口javascript文件,可以改为自己文件的名字,运行npm install安装bindings和nan

1
npm install

创建hash.cc(C++模块)

新建hash.cc文件,内容如下,用的是google v8引擎的API接口,如果想更深入的理解下面的代码,可查询V8引擎文档

#include <node.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

using namespace v8;

const char* ToCString(const String::Utf8Value& value) {
  return *value ? *value : "<string conversion failed>";
}


void userId2Long(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  if (args.Length() < 1) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong number of arguments")));
    return;
  }

  if (!args[0]->IsString()) {
    isolate->ThrowException(Exception::TypeError(
        String::NewFromUtf8(isolate, "Wrong arguments")));
    return;
  }
  long hash = 0L;
  String::Utf8Value str(args[0]);
  const char* hashStr = ToCString(str);
  for(size_t i = 0; i < strlen(hashStr); i++){
     hash = 47*hash + (long)hashStr[i];
  }
  hash = labs(hash);
  int size = 20;
  char *buffer = (char*)malloc(size);
  if(hash < 1000000000){
        memset(buffer,0,size);
        sprintf(buffer,"%ld",hash);
        hash = hash + 1000000000*(int)buffer[0];
  }
  memset(buffer,0,size);
  sprintf(buffer,"%ld",hash);
  Local<String> num = String::NewFromUtf8(isolate,buffer);
  args.GetReturnValue().Set(num);
}


void Init(Handle<Object> target){
   //此处导出userId2Long方法供nodejs调用
   NODE_SET_METHOD(target,"userId2Long",userId2Long);
}


NODE_MODULE(swcUtil,Init)

创建hash.js来调用C++模块

创建hash.js,内容如下

var addon = require('bindings')('swcUtil.node')
var ret = addon.userId2Long('4863896489364893')
console.log('ret :',ret)

创建binding.gyp,编译模块

创建binding.gyp,内容如下

{
  'targets': [
    {
      'target_name': 'swcUtil',
      'sources': [
        'hash.cc'
      ],
      'dependencies': [
      ]
    }
  ]
}

然后运行

1
node-gyp rebuild

没有任何报错的情况的下,会生成一个build目录

运行测试npm test

1
npm test

如果打印内容为ret :xxxxxx就可以恭喜你C++插件正常工作了

佘伟春 wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客!

热评文章