开发Node.js的Windows版C/C++原生扩展(node_0.10和node_0.12)
2012-12-10 18:46
639 查看
引言
Node.js[1]的C/C++原生扩展实质上就是动态连接库[2]。在Linux系统中,Node.js默认的编译器是gcc。目前有多种方法可用以方便地开发C/C++原生扩展[3],Node.js官方网站也有详细说明[2]。 Node.js在Windows环境中默认的编译器是VC,在然而 [3]介绍的方法并不适用于Windows环境,[2]只介绍了使用node-gypy[4]开发C/C++原生扩展的方法。 在参考[5]的基础上,本文使用CMake[6]和VISUAL C++ 2010 EXPRESS在Windows操作系统中开发Node.js的C/C++原生扩展。本文使用CMake创建VC工程文件,在CMakeLists.txt中设置工程属性,简化操作过程。使用node-gyp构建Node.js扩展
node-gyp是一个为Node.js编译原生扩展的跨平台命令行工具[4]。它使用Node.js语言编写。 node-gyp能编译多个版本的原生扩展。在编译过程中,node-gyp只下载相应版本的头文件和其它必要文件,原生扩展的版本与当地系统中Node.js版本没有依赖关系。使用CMAKE构建Node.js原生扩展
(下述样例只适用node_0.12等老版本 )[5]只介绍了如何向Node.js添加C++扩展函数, 本文以向Node.js添加一个C++扩展类为例,详细介绍在Windows操作系统中开发Node.js的C/C++原生扩展的过程。具体步骤如下:
1、安装CMake和Windows的VC编译器。我使用的是VISUAL C++ 2010 EXPRESS。
2、安装Windows版的Node.js。 最好是下载Node.js源代码编译生成Node.js可执行文件和库文件。
3、配置Node.js的C/C++原生扩展编译环境(node_0.10)
nodemodule
|__include
|__c-ares
|__ares.h
|__ares_version.h
|__ev
|__ev.h
|__uv-private
|__eio.h
|__ngx-queue.h
|__tree.h
|__uv-unix.h
|__uv-win.h
|__node.h
|__ node_buffer.h
|__node_object_wrap.h
|__node_version.h
|__uv.h
|__v8-debug.h
|__v8-preparser.h
|__ v8-profiler.h
|__ v8-testing.h
|__v8.h
|__v8stdint.h
|__lib
|__node.lib
|__src
|__tmp
|__CMakeLists.txt
4、创建VISUAL C++ 2010 EXPRESS的DLL工程。 我使用CMake创建的VC工程文件。
4.1 CMakeLists.txt
#====================================== # Project Name #====================================== SET( TARGETFILENAME "foo" ) PROJECT( ${TARGETFILENAME} ) #====================================== # CMake minimum version requirement setting #====================================== cmake_minimum_required(VERSION 2.6) #====================================== # mdo setting #====================================== IF(COMMAND CMAKE_POLICY) CMAKE_POLICY(SET CMP0003 NEW) ENDIF(COMMAND CMAKE_POLICY) #====================================== # node library #====================================== SET(NODE_LIBRARIES node.lib) SET(NODE_LIBRARY_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/lib ) #====================================== # node library setting #====================================== FIND_LIBRARY(NODE_LIBRARY NAMES node PATHS ${CMAKE_CURRENT_SOURCE_DIR}/lib ) #====================================== # - Setting search route #====================================== INCLUDE_DIRECTORIES( ${CMAKE_CURRENT_BINARY_DIR} include include/c-ares include/ev include/un-private ) SET( src src/mymodule.cc src/module.cc ) #====================================== # # Setting include library path # # Make sure it come before the target # #====================================== LINK_DIRECTORIES( ${NODE_LIBRARY_DIRS} ) ADD_LIBRARY ( ${TARGETFILENAME} SHARED ${src} ) #====================================== # changing target file suffix to .node #====================================== SET_TARGET_PROPERTIES(${TARGETFILENAME} PROPERTIES SUFFIX ".node") #====================================== # link library setting #====================================== TARGET_LINK_LIBRARIES( ${TARGETFILENAME} ${NODE_LIBRARIES} )
5、编写C++代码
5.1 mymodule.h
node_0.10
#ifndef NODE_MYMODULE_H_ #define NODE_MYMODULE_H_ #include <node.h> #include <v8.h> class MyModule: public node::ObjectWrap { public: MyModule(); virtual ~MyModule(); public: static void InitializeModule(v8::Handle target); static v8::Handle New(const v8::Arguments& args); public: static v8::Handle hello(const v8::Arguments& args); protected: static v8::Persistent constructor_template; }; #endif // NODE_MYMODULE_H_
node_0.12
#ifndef NODE_MYMODULE_H_ #define NODE_MYMODULE_H_ #include <node.h> #include <v8.h> class MyModule: public node::ObjectWrap { public: MyModule(); virtual ~MyModule(); public: static void InitializeModule(v8::Handle target); static void New(const v8::FunctionCallbackInfo<v8::Value>& args); public: static void hello(const v8::FunctionCallbackInfo<v8::Value>& args); protected: static v8::Persistent<v8::Function> constructor; }; #endif // NODE_MYMODULE_H_
5.2 mymodule.cc
node_0.10
#include "mymodule.h" #include <iostream> Persistent MyModule::constructor_template; MyModule::MyModule() { } MyModule::~MyModule() { } void MyModule::InitializeModule(Handle target) { HandleScope scope; Local < FunctionTemplate > t = FunctionTemplate::New(MyModule::New); constructor_template = Persistent::New(t); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); constructor_template->SetClassName(String::NewSymbol("MyModule")); NODE_SET_PROTOTYPE_METHOD(constructor_template, "hello", MyModule::hello); target->Set(String::NewSymbol("MyModule"), constructor_template->GetFunction()); } v8::Handle MyModule::New(const v8::Arguments& args) { v8::HandleScope scope; MyModule* ptr = new MyModule(); ptr->Wrap(args.Holder()); return args.This(); } v8::Handle MyModule::hello(const v8::Arguments& args) { HandleScope scope; bool result = true; std::cout << "hello." << std::endl; return scope.Close(v8::Boolean::New(result)); }
node_0.12
#include "mymodule.h" #include <iostream> Persistent<Function> MyModule::constructor; MyModule::MyModule() { } MyModule::~MyModule() { } void MyModule::InitializeModule(Handle<Object> exports) { Isolate* isolate = Isolate::GetCurrent(); // Prepare constructor template Local<FunctionTemplate> constructor_template = FunctionTemplate::New(isolate, New); constructor_template->SetClassName(String::NewFromUtf8(isolate, "MyModule")); constructor_template->InstanceTemplate()->SetInternalFieldCount(1); NODE_SET_PROTOTYPE_METHOD(constructor_template, "hello", MyModule::hello); constructor.Reset(isolate, constructor_template->GetFunction()); exports->Set(String::NewFromUtf8(isolate, "MyModule"), constructor_template->GetFunction()); } v8::Handle MyModule::New(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); if (args.IsConstructCall()) { // Invoked as constructor: `new MyModule(...)` MyModule* obj = new MyModule( ); obj->Wrap(args.This()); args.GetReturnValue().Set(args.This()); } else { // Invoked as plain function `<span style="font-family: Arial, Helvetica, sans-serif;">MyModule</span>(...)`, turn into construct call. const int argc = 1; Local<Value> argv[argc] = { args[0] }; Local<Function> cons = Local<Function>::New(isolate, constructor); args.GetReturnValue().Set(cons->NewInstance(argc, argv)); } } void MyModule::hello(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = Isolate::GetCurrent(); HandleScope scope(isolate); bool result = true; std::cout << "hello." << std::endl; args.GetReturnValue().Set(v8::Boolean::New(isolate,result)); return }
5.3 module.cc
node_0.10
/* * moule.cc * */ #include <node.h> #include <v8.h> #include "mymodule.h" using namespace v8; using namespace node; //extern "C" void init(Handle target) { HandleScope scope; MyModule::InitializeModule(target); }; NODE_MODULE(foo, init) // 模块名字 "foo" 必须和动态库名字一致
node_0.12
/* * moule.cc * */ #include <node.h> #include "mymodule.h" using namespace v8; void init(v8::Handle<v8::Object> target) { MyModule::InitializeModule(target); }; NODE_MODULE(foo, init) // 模块名字 "foo" 必须和动态库名字一致
6、编译
7、测试
7.1 测试脚本代码
var MyModule = require ("./foo").MyModule; var theModule = new MyModule(); console.log( theModule.hello() ) ;
参考文献
[1] Node.js. (2012年12月12日) http://nodejs.org/
[2] addons. (2012年12月12日) http://nodejs.org/api/addons.html
[3] (2012年12月12日) https://www.cloudkick.com/blog/2010/aug/23/writing-nodejs-native-extensions/
[4] node-gpy.(2012年12月12日) https://github.com/TooTallNate/node-gyp
[5] (2012年12月12日) http://cnodejs.org/topic/4f71e3688a04d82a3d264b5a
[6] CMake (2012年12月12日) http://www.cmake.org/
相关文章推荐
- 在Windows下开发Node.js的C/C++原生扩展
- [js插件开发教程]原生js仿jquery架构扩展开发选项卡插件
- Node.js项目实战-构建可扩展的Web应用(第一版):3 Node.js基于Mocha的测试驱动开发和行为驱动开发
- Node.app:用Node.js API开发iOS“原生”应用
- Node.js 原生模块开发方式变迁
- 编写Node.js原生扩展
- 从暴力到 NAN 到 NAPI——Node.js 原生模块开发方式变迁
- Node.js原生开发入门完全教程
- 30天了解30种技术系列---(4)Node.js神级开发工具-WebStorm
- node.js开发中使用Node Supervisor实现监测文件修改并自动重启应用
- Node.js开发——解决Cesium视角切换的异常
- node.js开发之给webstrom9换个主题
- 快速搭建 Node.js 开发环境
- 从久负盛名的GoDaddy开发革命来看Node.js的风靡程度
- ionic+nodejs开发遇到的跨域和post请求数据问题
- 搭建一个开发Predix软件的Windows系统(5)配置Node.js
- Node.js开发指南之一:基本概念与开发环境的配置
- Node.js项目实战-构建可扩展的Web应用(第一版): 7 使用ORM类库Mongoose提升你的Node.js数据
- Node.js入门之快速搭建开发环境
- 用NodeJS+Mongodb+Pug开发博客网站