Node.js 添加 C/C++ Addon

一直想要开一个博客,总结记录一下自己学到的东西,今天终于动笔写了第一篇,希望能够坚持下去。

我的博客主要会分享一些自己最近学习的东西,主要是给自己看的,如果能帮到别人的话当然最好了。

----------------------我是华丽的分割线-------------------------------

实验室最近正在做一个基于Node.js的项目,之前对Front End的知识了解很少,所以从JavaScript一点点学起慢慢熟悉。 我的主要任务是把一个已经写好的C语言程序转化为Node.js的Library可以随时调用运行。

按照Node官方给的文档,我从最基础的Hello World开始,学习如何添加Addon,以下是结合官方的documentation我自己的总结。

Node.js Addons 是C/C++写成的Objects,可以通过require()调用,用起来就像Node自带的module一样,主要用于提供介于Node.js和C/C++库之间的接口。

实现Addons所需要的背景知识主要包括:V8 JavaScript Engine, Libuv, Node.js内部library, Node.js内部库自带一些C/C++ API可以供Addons使用。

从最简单的开始,添加一个C++ Addon实现的功能等同于: module.exports.hello = function(){return ‘world‘;}; 调用这个函数,可以返回字符串“world”;

Step1

首先需要通过运行命令’npm init‘创建一个 package.json文件的框架,用来记录所需的配置文件

Step2

安装 “NAN”。 NAN是一个介于 C++源程序,Node,和 V8 API之间的抽象层。NAN的存在是为了保证当V8的API更新后,之前的程序仍可以运行。 当V8的API更新后,只需更新NAN便可以保证已经写好的程序可以继续运行,避免了修改源代码的问题。

通过运行‘npm install [email protected] --save‘来安装NAN,并将NAN作为 dependency存储在package.json里。

Step3

所有的Addons 都会使用[node-gyp]编译,在package.json中加入‘gypfile:true’来使能nodel-gyp编译。 当 node-gyp被调用时,会寻找一个与‘package.json’在同一目录下的‘binding.gyp’ file。 这个binding文件用YAML写成,用于描述build的细节,比如源文件以及所需的dependencies。node-gyp会参考我们自己写成的binding.gyp文件和一个common.gypi来进行编译,common.gypi描述了node.js会用到的设置和可能的dependencies。 因为我们的代码将会在node下编译,所以必须要有common.gypi file用于描述node的环境设置。另外,我们还需要下载和我们正在运行的版本对应的tarball。(原文是it must also download the complete tarball of the particular release you are running,我也没有很理解这句话,看懂的朋友希望指正)。

文档中给出了简单的binding文件:

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
span.s1 { }

{

"targets": [

{

"target_name": "hello",

"sources": [ "hello.cc" ],

"include_dirs": [

"<!(node -e \"require(‘nan‘)\")"

]

}

]

}

我们只要新建一个binding.gyp file并复制这段代码就可以了。

这段代码做了如下几件事:1 命名目标Addon为“hello”,最终输出的文件名将会是hello.node. 2 需要编译的源文件是"hello.cc" 3 规定了编译时[NAN]的路径

Step4

编写hello.cc的源代码。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b; min-height: 13.0px }
span.s1 { }

#include <nan.h>

using namespace v8;

NAN_METHOD(Method) {

NanScope();

NanReturnValue(String::New("world"));

}

void Init(Handle<Object> exports) {

exports->Set(NanSymbol("hello"), FunctionTemplate::New(Method)->GetFunction());

}

NODE_MODULE(hello, Init)

现在从下到上来分析这段代码:

NODE_MODULE(hello,Init)定义了addon的entry-point, 参数“hello”必须与binding file中的target相同,第二个参数“Init“指向了要调用的函数。

void Init(Handle<Object> exports) {

exports->Set(NanSymbol("hello"), FunctionTemplate::New(Method)->GetFunction());

}

按照NODE_MODULE的定义,这一函数是addon实际的entry-point。 这一函数有两个参数: ‘exports’ 与js文件中的‘module.exports‘相同,第二个参数(本例中已经被忽略)是‘module’,类似js文件中的‘module’。一般情况下,我们会给exports attach一些属性,但是我们也可以使用‘module’(第二个参数)来替换‘module’的exports属性,这样就只能 export a single thing, e.g. module.exports = function(){}.

本例中, 我们只需要attach一个“hello” property 在module.exports中。所以我们给V8 的一个‘Function’对象[SET]一个 V8’String‘ 属性。 首先,我们使用 NanSymbol() 函数新建一个’symbol‘ 字符串(之后可以重复使用). 我们使用 V8 ‘FunctionTemplate‘ 把一个普通的 C++函数转换为一个 V8-callable function. 在我们的例子中,这个‘C++函数’是Method function。

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
span.s1 { }
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
span.s1 { }

NAN_METHOD(Method) {

NanScope();

NanReturnValue(String::New("world"));

}

这里体现出了NAN的用处。 V8 API的改变使得 将C++ Addon 添加到不同版本的node变得很困难。 所以NAN提供了一个简单的mapping,我们可以定义一个 ‘FunctionTemplate’可以接受的 V8 compatible function。 在最近的V8中,NAN_METHOD(Method) 可以扩展成 ‘void Method(const v8::FunctionCallbackInfo<v8::Value>& args)‘,这是一个 V8 callable function的标准signature。‘args‘ 包括了 call information, 比如 JavaScript function的参数,设置返回值等。

NanScope() 定义了新建的‘handles’的生命周期。当我们在函数开始时使用NanScope时表示所有的 我们使用的V8 object存活的时间与该function相等。 如果没有这句代码,V8 Object将不会在function结束时被回收。

NanReturnValue设置了函数的返回值。在本例子中, 我们新建了一个简单的“world” 字符串,这个字符串将会被暴露为标准的JavaScript String。

Step 5

编译我们的Addon。 通过‘sudo npm install node-gyp -g‘ 安装‘node-gyp‘。

运行‘node-gyp configure‘ 来设置build fixtures. 会生成一个 ‘Makefile‘ 文件

运行‘node-gyp build‘启动编译过程。 或者可以使用‘node-gyp rebuild‘ 将 ‘configure‘ & ’build‘和成一步。成功以后我们就有了一个可以使用的addon binary文件。Node可以载入并运行这个文件像载入普通.js module file 一样。

Step 6

编写JavaScript

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
p.p2 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b; min-height: 13.0px }
span.s1 { }

var addon = require(‘./build/Release/hello.node‘);

console.log(addon.hello());

调用addon的hello()function,输出“world”

p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; color: #d12f1b }
span.s1 { }

时间: 2024-10-18 22:22:35

Node.js 添加 C/C++ Addon的相关文章

【Node.js】 初体验

1.新建一个app.js文件 2.使用npm install http 导入http模块 3.直接上代码 //引入http模块 var http = require('http'); //创建服务器 var app=http.createServer(function (request, response) { // 发送 HTTP 头部 // HTTP 状态值: 200 : OK // 内容类型: text/plain response.writeHead(200, {'Content-Typ

Node.js C++ addon编写实战(一)之node-gyp

http://deadhorse.me/nodejs/2012/10/08/c_addon_in_nodejs_node_gyp.html 这是一个三篇的系列文章,记录Node.js C++扩展开发中的一些经验与坑.Node.js C++ addon编写实战(一)之node-gypNode.js C++ addon编写实战(二)之对象转换Node.js C++ addon编写实战(三)之Buffer 补上第四篇:Node.js C++ addon编写实战(四)之兼容v0.11+与nan模块 从n

用vs2013开发node.js的addon.

? ? 下载node.js的源代码. https://github.com/joyent/node 如果用svn下载,后面加上/trunk,以免把用不着的branches也下载下来,浪费时间. 安装VS, express版本也可以.我安装的是vs2013 ultimate. 安装python 2.x http://www.python.org/download/ 注意不能是3.x, 因为node-gyp目前需要2.x. 我安装的是2.7. 用命令行工具,Cd到node源代码目录,运行vcbuil

详解Node.js API系列C/C++ Addons(3) 程序实例

http://blog.whattoc.com/2013/09/08/nodejs_api_addon_3/ 再续前文,前文介绍了node.js 的addon用法和google v8 引擎,下面,我们进入真正的编码,下面将会通过六个例子,学习node addon 范例,了解addon编程的特性 创建一个空项目 随机数模块 向模块传递参数 回调函数处理 线程处理 对象管理 创建一个空项目 vi modulename.cpp #include <node.h> void RegisterModul

用Node.js 将bugzilla上的bug列表导入到excel表格里

公司用bugzilla管理产品bug,最近用Node.js做了个东西,方便能够把bug的相关信息导入到excel表格里,好做后续的管理分析. 直接贴代码,写上注释好了.转载请注明出处. var request = require("request") var cheerio = require("cheerio"); var Excel = require('exceljs'); var colors = require("colors"); v

Node.js开发 ---- 模块 require和 exports

蟹蟹https://liuzhichao.com/p/1669.html 什么是模块? Node.js通过实现CommonJS的Modules/1.0标准引入了模块(module)概念,模块是Node.js的基本组成部分.一个node.js文件就是一个模块,也就是说文件和模块是一一对应的关系.这个文件可以是JavaScript代码,JSON或者编译过的C/C++扩展. Node.js的模块分为两类,一类为原生(核心)模块,一类为文件模块. 在文件模块中,又分为3类模块.这三类文件模块以后缀来区分

(译+注解)node.js的C++扩展入门

声明:本文主要翻译自node.js addons官方文档.部分解释为作者自己添加. 编程环境: 1. 操作系统 Mac OS X 10.9.51. node.js v4.4.22. npm v3.9.2 本文将介绍node.js中编写C++扩展的入门知识. 1. 基本知识介绍 在node.js中,除了用js写代码以外,还可以使用C++编写扩展,这有点类似DLL,动态链接进js代码中.使用上也相当方便,只需用require包含,这和一般的js模块并没有什么区别.C++扩展为js和C++代码的通信提

[ 转]Node.js模块 require和 exports

什么是模块? node.js通过实现CommonJS的Modules/1.0标准引入了模块(module)概念,模块是Node.js的基本组成部分.一个node.js文件就是一个模块,也就是说文件和模块是一一对应的关系.这个文件可以是JavaScript代码,JSON或者编译过的C/C++扩展. Node.js的模块分为两类,一类为原生(核心)模块,一类为文件模块. 在文件模块中,又分为3类模块.这三类文件模块以后缀来区分,Node.js会根据后缀名来决定加载方法. .js.通过fs模块同步读取

Node.js C++扩展实现

因为有了Node.js,JavaScript可以被用于服务端编程.通过各种扩展,Node.js可以变得非常强大.今天分享下怎样用C++创建Node.js扩展. 参考原文:Making Dynamsoft Barcode SDK an Addon for Node.js 搭建Nodejs开发环境 要构建扩展,需要安装node-gyp: npm install -g node-gyp 这个库里面包涵了JavaScript v8引擎所需要的头文件以及依赖库. 创建一个C/C++文件dbr.cc以及配置