nodejs添加C++模块
来源:互联网 发布:编程c图形库砖块金字塔 编辑:程序博客网 时间:2024/06/05 02:54
环境:
win7
VS2010
node-gyp:1.0.1
python:2.7.3
nodejs:0.10.32
HELLO
Node为了实现跨平台的编译,采用了Google的GYP(Generate Your Projects)来对项目进行管理。
安装node-gyp
npm isntall -g node-gyp
新建hello.cc:
Node的JavaScript引擎用的是Google开源的V8 JavaScript引擎(Chrome浏览器所用的引擎),所以简单介绍下v8中的一些概念:
Handle:一个handle就是指向一个对象的指针。v8中所有的对象都是使用handle来进行访问,之所以用它是因为v8的垃圾回收器需要。
HandleScope:可以把它想象成是多个Handle的一个容器。
#include <node.h>#include <v8.h>using namespace v8;Handle<Value> Method(const Arguments& args) { HandleScope scope; return scope.Close(String::New("world"));}void init(Handle<Object> exports) { exports->Set(String::NewSymbol("hello"), FunctionTemplate::New(Method)->GetFunction());}NODE_MODULE(hello, init)
新建binding.gyp:
binding.gyp是默认的项目定义文件
{ "targets": [ { "target_name": "hello", "sources": [ "hello.cc" ] } ]}
之后我们以binding.gyp文件来生成Makefile等编译所需的文件:
node-gyp configure
E:\workspace\addon>node-gyp configuregyp info it worked if it ends with okgyp info using node-gyp@1.0.2gyp info using node@0.10.32 | win32 | x64gyp info spawn C:\Python27\python.exegyp info spawn args [ 'C:\\Users\\ucloud01\\AppData\\Roaming\\npm\\node_modules\\node-gyp\\gyp\\gyp_main.py',gyp info spawn args 'binding.gyp',gyp info spawn args '-f',gyp info spawn args 'msvs',gyp info spawn args '-G',gyp info spawn args 'msvs_version=auto',gyp info spawn args '-I',gyp info spawn args 'E:\\workspace\\addon\\build\\config.gypi',gyp info spawn args '-I',gyp info spawn args 'C:\\Users\\ucloud01\\AppData\\Roaming\\npm\\node_modules\\node-gyp\\addon.gypi',gyp info spawn args '-I',gyp info spawn args 'C:\\Users\\ucloud01\\.node-gyp\\0.10.32\\common.gypi',gyp info spawn args '-Dlibrary=shared_library',gyp info spawn args '-Dvisibility=default',gyp info spawn args '-Dnode_root_dir=C:\\Users\\ucloud01\\.node-gyp\\0.10.32',gyp info spawn args '-Dmodule_root_dir=E:\\workspace\\addon',gyp info spawn args '--depth=.',gyp info spawn args '--no-parallel',gyp info spawn args '--generator-output',gyp info spawn args 'E:\\workspace\\addon\\build',gyp info spawn args '-Goutput_dir=.' ]gyp info ok
执行完成之后,在项目目录下会生成一个build目录,里边是gyp自动生成的一些编译所需文件。这一步完成之后,我们来进行编译操作:
node-gyp build
E:\workspace\addon>node-gyp buildgyp info it worked if it ends with okgyp info using node-gyp@1.0.2gyp info using node@0.10.32 | win32 | x64gyp info spawn C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exegyp info spawn args [ 'build/binding.sln',gyp info spawn args '/clp:Verbosity=minimal',gyp info spawn args '/nologo',gyp info spawn args '/p:Configuration=Release;Platform=x64' ]在此解决方案中一次生成一个项目。若要启用并行生成,请添加“/m”开关。 hello.ccC:\Users\ucloud01\.node-gyp\0.10.32\deps\v8\include\v8.h(184): warning C4506: 内联函数“v8::Persistent<T> v8::Persistent<T>::New(v8::Handle<T>)”没有定义 [E:\workspace\addon\build\hello.vcxproj] with [ T=v8::Object ] 正在创建库 E:\workspace\addon\build\Release\hello.lib 和对象 E:\workspace\addon\bu ild\Release\hello.exp 正在生成代码 已完成代码的生成 hello.vcxproj -> E:\workspace\addon\build\Release\\hello.nodegyp info ok
如果执行没有问题的话,在build/Release目录下会生成hello.node文件,即我们创建的hello模块
测试:hello.js
var addon = require('./build/Release/hello');console.log(addon.hello()); // 'world'输出:
E:\workspace\addon>node helloworld
向C++模块传递参数
addon.cc:
#define BUILDING_NODE_EXTENSION#include <node.h>using namespace v8;Handle<Value> Add(const Arguments& args) { HandleScope scope; if (args.Length() < 2) { ThrowException(Exception::TypeError(String::New("Wrong number of arguments"))); return scope.Close(Undefined()); } if (!args[0]->IsNumber() || !args[1]->IsNumber()) { ThrowException(Exception::TypeError(String::New("Wrong arguments"))); return scope.Close(Undefined()); } Local<Number> num = Number::New(args[0]->NumberValue() + args[1]->NumberValue()); return scope.Close(num);}void Init(Handle<Object> exports) { exports->Set(String::NewSymbol("add"), FunctionTemplate::New(Add)->GetFunction());}NODE_MODULE(addon, Init)binding.gyp:
{ "targets": [ { "target_name": "addon", "sources": [ "addon.cc" ] } ]}node-gyp configure
node-gyp build
test:
addon_test.js
var addon = require('./src/build/Release/addon');console.log( 'This should be 9:', addon.add(4,5) );
result:
E:\workspace\addon>node addon_test.jsThis should be 9: 9
回调
传递一个javascript函数到C++模板处理
addon.cc
#define BUILDING_NODE_EXTENSION#include <node.h>using namespace v8;Handle<Value> RunCallback(const Arguments& args) { HandleScope scope; Local<Function> cb = Local<Function>::Cast(args[0]); const unsigned argc = 1; Local<Value> argv[argc] = { Local<Value>::New(String::New("hello world")) }; cb->Call(Context::GetCurrent()->Global(), argc, argv); return scope.Close(Undefined());}void Init(Handle<Object> exports, Handle<Object> module) { module->Set(String::NewSymbol("exports"), FunctionTemplate::New(RunCallback)->GetFunction());}NODE_MODULE(addon, Init)test
addon_test.js:
var addon = require('./src/build/Release/addon');addon(function(msg){ console.log(msg); // 'hello world'});
E:\workspace\addon>node addon_test.jshello world
用C++模块创建object代理
addon.cc:#define BUILDING_NODE_EXTENSION#include <node.h>using namespace v8;Handle<Value> CreateObject(const Arguments& args) { HandleScope scope; Local<Object> obj = Object::New(); obj->Set(String::NewSymbol("msg"), args[0]->ToString()); return scope.Close(obj);}void Init(Handle<Object> exports, Handle<Object> module) { module->Set(String::NewSymbol("exports"), FunctionTemplate::New(CreateObject)->GetFunction());}NODE_MODULE(addon, Init)addon_test.js:
var addon = require('./src/build/Release/addon');var obj1 = addon('hello');var obj2 = addon('world');console.log(obj1.msg+' '+obj2.msg); // 'hello world'result:
E:\workspace\addon>node addon_test.jshello world
函数代理
addon.cc
#define BUILDING_NODE_EXTENSION#include <node.h>using namespace v8;Handle<Value> MyFunction(const Arguments& args) { HandleScope scope; return scope.Close(String::New("hello world"));}Handle<Value> CreateFunction(const Arguments& args) { HandleScope scope; Local<FunctionTemplate> tpl = FunctionTemplate::New(MyFunction); Local<Function> fn = tpl->GetFunction(); fn->SetName(String::NewSymbol("theFunction")); // omit this to make it anonymous return scope.Close(fn);}void Init(Handle<Object> exports, Handle<Object> module) { module->Set(String::NewSymbol("exports"), FunctionTemplate::New(CreateFunction)->GetFunction());}NODE_MODULE(addon, Init)addon_test.js
var addon = require('./src/build/Release/addon');var fn = addon();console.log(fn()); // 'hello world'result:
E:\workspace\addon>node addon_test.jshello world
封装C++对象
c++主文件 addon.cc
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;void InitAll(Handle<Object> exports) { MyObject::Init(exports);}NODE_MODULE(addon, InitAll)在myobject.h中继承node::ObjectWrap
#ifndef MYOBJECT_H#define MYOBJECT_H#include <node.h>class MyObject : public node::ObjectWrap { public: static void Init(v8::Handle<v8::Object> exports); private: explicit MyObject(double value = 0); ~MyObject(); static v8::Handle<v8::Value> New(const v8::Arguments& args); static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args); static v8::Persistent<v8::Function> constructor; double value_;};#endifmyobject.cc实现函数
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;Persistent<Function> MyObject::constructor;MyObject::MyObject(double value) : value_(value) {}MyObject::~MyObject() {}void MyObject::Init(Handle<Object> exports) { // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); constructor = Persistent<Function>::New(tpl->GetFunction()); exports->Set(String::NewSymbol("MyObject"), constructor);}Handle<Value> MyObject::New(const Arguments& args) { HandleScope scope; if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); return args.This(); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; return scope.Close(constructor->NewInstance(argc, argv)); }}Handle<Value> MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This()); obj->value_ += 1; return scope.Close(Number::New(obj->value_));}test:
var addon = require('./src/build/Release/addon');var obj = new addon.MyObject(10);console.log( obj.plusOne() ); // 11console.log( obj.plusOne() ); // 12console.log( obj.plusOne() ); // 13记得修改binding.gyp:
{ "targets": [ { "target_name": "addon", "sources": [ "addon.cc" , "myobject.cc"] } ]}result:
E:\workspace\addon>node addon_test.js111213
封装对象的代理
addon.cc
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;Handle<Value> CreateObject(const Arguments& args) { HandleScope scope; return scope.Close(MyObject::NewInstance(args));}void InitAll(Handle<Object> exports, Handle<Object> module) { MyObject::Init(); module->Set(String::NewSymbol("exports"), FunctionTemplate::New(CreateObject)->GetFunction());}NODE_MODULE(addon, InitAll)myobject.h
#define BUILDING_NODE_EXTENSION#ifndef MYOBJECT_H#define MYOBJECT_H#include <node.h>class MyObject : public node::ObjectWrap { public: static void Init(); static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args); private: explicit MyObject(double value = 0); ~MyObject(); static v8::Handle<v8::Value> New(const v8::Arguments& args); static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args); static v8::Persistent<v8::Function> constructor; double value_;};#endifmyobject.cc
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;Persistent<Function> MyObject::constructor;MyObject::MyObject(double value) : value_(value) {}MyObject::~MyObject() {}void MyObject::Init() { // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); constructor = Persistent<Function>::New(tpl->GetFunction());}Handle<Value> MyObject::New(const Arguments& args) { HandleScope scope; if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); return args.This(); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; return scope.Close(constructor->NewInstance(argc, argv)); }}Handle<Value> MyObject::NewInstance(const Arguments& args) { HandleScope scope; const unsigned argc = 1; Handle<Value> argv[argc] = { args[0] }; Local<Object> instance = constructor->NewInstance(argc, argv); return scope.Close(instance);}Handle<Value> MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This()); obj->value_ += 1; return scope.Close(Number::New(obj->value_));}test:
var createObject = require('./src/build/Release/addon');var obj = createObject(10);console.log( obj.plusOne() ); // 11console.log( obj.plusOne() ); // 12console.log( obj.plusOne() ); // 13var obj2 = createObject(20);console.log( obj2.plusOne() ); // 21console.log( obj2.plusOne() ); // 22console.log( obj2.plusOne() ); // 23result:
E:\workspace\addon>node addon_test.js111213212223传递封装的对象
addon.cc
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;Handle<Value> CreateObject(const Arguments& args) { HandleScope scope; return scope.Close(MyObject::NewInstance(args));}Handle<Value> Add(const Arguments& args) { HandleScope scope; MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>( args[0]->ToObject()); MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>( args[1]->ToObject()); double sum = obj1->getValue() + obj2->getValue(); return scope.Close(Number::New(sum));}void InitAll(Handle<Object> exports) { MyObject::Init(); exports->Set(String::NewSymbol("createObject"), FunctionTemplate::New(CreateObject)->GetFunction()); exports->Set(String::NewSymbol("add"), FunctionTemplate::New(Add)->GetFunction());}NODE_MODULE(addon, InitAll)myobject.h
#define BUILDING_NODE_EXTENSION#ifndef MYOBJECT_H#define MYOBJECT_H#include <node.h>class MyObject : public node::ObjectWrap { public: static void Init(); static v8::Handle<v8::Value> NewInstance(const v8::Arguments& args); double getValue() const {return value_;} private: explicit MyObject(double value = 0); ~MyObject(); static v8::Handle<v8::Value> New(const v8::Arguments& args); static v8::Handle<v8::Value> PlusOne(const v8::Arguments& args); static v8::Persistent<v8::Function> constructor; double value_;};#endifmyobject,cc
<pre name="code" class="cpp">
#define BUILDING_NODE_EXTENSION#include <node.h>#include "myobject.h"using namespace v8;Persistent<Function> MyObject::constructor;MyObject::MyObject(double value) : value_(value) {}MyObject::~MyObject() {}void MyObject::Init() { // Prepare constructor template Local<FunctionTemplate> tpl = FunctionTemplate::New(New); tpl->SetClassName(String::NewSymbol("MyObject")); tpl->InstanceTemplate()->SetInternalFieldCount(1); // Prototype tpl->PrototypeTemplate()->Set(String::NewSymbol("plusOne"), FunctionTemplate::New(PlusOne)->GetFunction()); constructor = Persistent<Function>::New(tpl->GetFunction());}Handle<Value> MyObject::New(const Arguments& args) { HandleScope scope; if (args.IsConstructCall()) { // Invoked as constructor: `new MyObject(...)` double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue(); MyObject* obj = new MyObject(value); obj->Wrap(args.This()); return args.This(); } else { // Invoked as plain function `MyObject(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; return scope.Close(constructor->NewInstance(argc, argv)); }}Handle<Value> MyObject::NewInstance(const Arguments& args) { HandleScope scope; const unsigned argc = 1; Handle<Value> argv[argc] = { args[0] }; Local<Object> instance = constructor->NewInstance(argc, argv); return scope.Close(instance);}Handle<Value> MyObject::PlusOne(const Arguments& args) { HandleScope scope; MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.This()); obj->value_ += 1; return scope.Close(Number::New(obj->value_));}
test:
var addon = require('./src/build/Release/addon');var obj1 = addon.createObject(10);var obj2 = addon.createObject(20);var result = addon.add(obj1, obj2);console.log(result); // 30result:
E:\workspace\addon>node addon_test.js30这里把文档中的
double Value() const {return value_;}
改成了
double getValue() const {return value_;}不然会报错
1 0
- nodejs添加C++模块
- nodejs为其他模块添加EventEmitter
- Nodejs 模块
- nodejs模块
- Nodejs 模块
- nodejs-模块
- NodeJS-模块
- NodeJS模块
- nodejs 模块
- nodejs模块
- Nodejs 模块
- nodejs 模块与es6模块
- nodejs模块之fs模块
- 在android上向nodejs中添加第三方node模块
- NodeJS 常用模块推荐
- nodejs event模块
- NodeJS 常用模块推荐
- nodejs文件夹遍历模块
- 深入浅出REST
- poj 2411 Mondriaan's Dream
- MAC上的PHP工作环境搭建
- 'telent' 不是内部或外部命令,也不是可运行的程序或批处理文件。
- uva 10453(dp)
- nodejs添加C++模块
- kafka安装
- 黑马程序员--c语言:进制、变量的内存分析、类型说明符、位运算、char类型、数组
- 黑马程序员--------java 多线程
- 第十六周项目二-用指针玩字符串-1
- 浅析命令模式
- Android 加载列表数据
- Shell函数 传递多个参数
- flash ActionScript 函数的调用