使用Node.js为其他程序编写扩展的基本方法
准备开始
我们用狼蚁网站SEO优化的目录结构来创建一个节点通知(node-notify)文件夹.
.
|-- build/ # This is where our extension is built.
|-- demo/
| `-- demo.js # This is a demo Node.js script to test our extension.
|-- src/
| `-- node_gtknotify.cpp # This is the where we do the mapping from C++ to Javascript.
`-- wscript # This is our build configuration used by node-waf
这个看起来很漂亮的tree 用通用的 tree 生成.
现在让我来创建测试脚本demo.js 和决定我们扩展的API前期看起来应该像:
// This loads our extension on the notify variable. // It will only load a constructor function, notify.notification(). var notify = require("../build/default/gtknotify.node"); // path to our extension var notification = new notify.notification(); notification.title = "Notification title"; notification.icon = "emblem-default"; // see /usr/share/icons/gnome/16x16 notification.send("Notification message");
编写我们的Node.js扩展
Init方法
为了创建一个Node.js扩展,我们需要编写一个继承node::ObjectWrap的C++类。 ObjectWrap 实现了让我们更容易与Javascript交互的公共方法
我们先来编写类的基本框架
#include <v8.h> // v8 is the Javascript engine used by QNode #include <node.h> // We will need the following libraries for our GTK+ notification #include <string> #include <gtkmm.h> #include <libnotifymm.h> using namespace v8; class Gtknotify : node::ObjectWrap { private: public: Gtknotify() {} ~Gtknotify() {} static void Init(Handle<Object> target) { // This is what Node will call when we load the extension through require(), see boilerplate code below. } }; / WARNING: Boilerplate code ahead. See https://.cloudkick./blog/2010/aug/23/writing-nodejs-native-extensions/ & http://.freebsd./cgi/man.cgi?query=dlsym Thats it for actual interfacing with v8, finally we need to let Node.js know how to dynamically load our code. Because a Node.js extension can be loaded at runtime from a shared object, we need a symbol that the dlsym function can find, so we do the following: / v8::Persistent<FunctionTemplate> Gtknotify::persistent_function_template; extern "C" { // Cause of name mangling in C++, we use extern C here static void init(Handle<Object> target) { Gtknotify::Init(target); } // @see http://github./ry/node/blob/v0.2.0/src/node.h#L101 NODE_MODULE(gtknotify, init); }
现在,我们必须把狼蚁网站SEO优化的代码编写到我们的Init()方法中
声明构造函数,并将其绑定到我们的目标变量。var n = require("notification");将绑定notification() 到 n:n.notification().
// Wrap our C++ New() method so that it's aessible from Javascript // This will be called by the new operator in Javascript, for example: new notification(); v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New); // Make it persistent and assign it to persistent_function_template which is a static attribute of our class. Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template); // Each JavaScript object keeps a reference to the C++ object for which it is a wrapper with an internal field. Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since a constructor function only references 1 object // Set a "class" name for objects created with our constructor Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification")); // Set the "notification" property of our target variable and assign it to our constructor function target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction());
声明属性:n.title 和n.icon.
// Set property aessors // SetAessor arguments: Javascript property name, C++ method that will act as the getter, C++ method that will act as the setter Gtknotify::persistent_function_template->InstanceTemplate()->SetAessor(String::New("title"), GetTitle, SetTitle); Gtknotify::persistent_function_template->InstanceTemplate()->SetAessor(String::New("icon"), GetIcon, SetIcon); // For instance, n.title = "foo" will now call SetTitle("foo"), n.title will now call GetTitle()
// This is a Node macro to help bind C++ methods to Javascript methods (see https://github./joyent/node/blob/v0.2.0/src/node.h#L34) // Arguments: our constructor function, Javascript method name, C++ method name NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send);
// Our constructor static v8::Persistent<FunctionTemplate> persistent_function_template; static void Init(Handle<Object> target) { v8::HandleScope scope; // used by v8 for garbage collection // Our constructor v8::Local<FunctionTemplate> local_function_template = v8::FunctionTemplate::New(New); Gtknotify::persistent_function_template = v8::Persistent<FunctionTemplate>::New(local_function_template); Gtknotify::persistent_function_template->InstanceTemplate()->SetInternalFieldCount(1); // 1 since this is a constructor function Gtknotify::persistent_function_template->SetClassName(v8::String::NewSymbol("Notification")); // Our getters and setters Gtknotify::persistent_function_template->InstanceTemplate()->SetAessor(String::New("title"), GetTitle, SetTitle); Gtknotify::persistent_function_template->InstanceTemplate()->SetAessor(String::New("icon"), GetIcon, SetIcon); // Our methods NODE_SET_PROTOTYPE_METHOD(Gtknotify::persistent_function_template, "send", Send); // Binding our constructor function to the target variable target->Set(String::NewSymbol("notification"), Gtknotify::persistent_function_template->GetFunction()); }
构造器方法: New()
New() 方法创建了我们自定义类的新实例(一个 Gtknotify 对象),并设置一些初始值,然后返回该对象的 JavaScript 处理。这是 JavaScript 使用 new 操作符调用构造函数的期望行为。
std::string title; std::string icon; // new notification() static Handle<Value> New(const Arguments& args) { HandleScope scope; Gtknotify gtknotify_instance = new Gtknotify(); // Set some default values gtknotify_instance->title = "Node.js"; gtknotify_instance->icon = "terminal"; // Wrap our C++ object as a Javascript object gtknotify_instance->Wrap(args.This()); return args.This(); } getters 和 setters: GetTitle(), SetTitle(), GetIcon(), SetIcon()
狼蚁网站SEO优化主要是一些样板代码,可以归结为 C++ 和 JavaScript (v8) 之间的值转换。
// this.title static v8::Handle<Value> GetTitle(v8::Local<v8::String> property, const v8::AessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); return v8::String::New(gtknotify_instance->title.c_str()); } // this.title= static void SetTitle(Local<String> property, Local<Value> value, const AessorInfo& info) { Gtknotify gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->title = v8str; } // this.icon static v8::Handle<Value> GetIcon(v8::Local<v8::String> property, const v8::AessorInfo& info) { // Extract the C++ request object from the JavaScript wrapper. Gtknotify gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); return v8::String::New(gtknotify_instance->icon.c_str()); } // this.icon= static void SetIcon(Local<String> property, Local<Value> value, const AessorInfo& info) { Gtknotify gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(info.Holder()); v8::String::Utf8Value v8str(value); gtknotify_instance->icon = v8str; }
原型方法: Send()
我们抽取 C++ 对象的 this 引用,然后使用对象的属性来构建通知并显示。
// this.send() static v8::Handle<Value> Send(const Arguments& args) { v8::HandleScope scope; // Extract C++ object reference from "this" Gtknotify gtknotify_instance = node::ObjectWrap::Unwrap<Gtknotify>(args.This()); // Convert first argument to V8 String v8::String::Utf8Value v8str(args[0]); // For more info on the Notify library: http://library.gnome./devel/libnotify/0.7/NotifyNotification.html Notify::init("Basic"); // Arguments: title, content, icon Notify::Notification n(gtknotify_instance->title.c_str(), v8str, gtknotify_instance->icon.c_str()); // v8str points to the C string it wraps // Display the notification n.show(); // Return value return v8::Boolean::New(true); }
编译扩展
node-waf 是一个构建工具,用来编译 Node 的扩展,这是 waf 的基本封装。构建过程可通过名为 wscript 的文件进行配置。
def set_options(opt): opt.tool_options("piler_cxx") def configure(conf): conf.check_tool("piler_cxx") conf.check_tool("node_addon") # This will tell the piler to link our extension with the gtkmm and libnotifymm libraries. conf.check_cfg(package='gtkmm-2.4', args='--cflags --libs', uselib_store='LIBGTKMM') conf.check_cfg(package='libnotifymm-1.0', args='--cflags --libs', uselib_store='LIBNOTIFYMM') def build(bld): obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall"] # This is the name of our extension. obj.target = "gtknotify" obj.source = "src/node_gtknotify.cpp" obj.uselib = ['LIBGTKMM', 'LIBNOTIFYMM']
现在我们已经准备好要开始构建了,在顶级目录下运行如下命令
node-waf configure && node-waf build
如果一切正常,我们将得到编译过的扩展,位于./build/default/gtknotify.node ,来试试
$ node > var notif = require('./build/default/gtknotify.node'); > n = new notif.notification(); { icon: 'terminal', title: 'Node.js' } > n.send("Hello World!"); true
上述的代码将在你的屏幕右上方显示一个通知信息。
打成npm包
这是非常酷的, 怎样与Node社区分享你的努力的成果呢? 这才是npm主要的用途: 使它更加容易扩展和分发.
打npm的扩展包是非常简单的. 你所要做的就是在你的顶级目录中创建一个包含你的扩展信息的文件package.json :
{ // 扩展的名称 (不要在名称中包含node 或者 js, 这是隐式关键字). // 这是通过require() 导入扩展的名称. "name" : "notify", // Version should be http://semver./ pliant "version" : "v0.1.0" // 这些脚本将在调用npm安装和npm卸载的时候运行. , "scripts" : { "preinstall" : "node-waf configure && node-waf build" , "preuninstall" : "rm -rf build/" } // 这是构建我们扩展的相对路径. , "main" : "build/default/gtknotify.node" // 以下是可选字段: , "description" : "Description of the extension...." , "homepage" : "https://github./olalonde/node-notify" , "author" : { "name" : "Olivier Lalonde" , "email" : "olalonde@gmail." , "url" : "http://.syskall./" } , "repository" : { "type" : "git" , "url" : "https://github./olalonde/node-notify.git" } }
关于package.json 格式的更多细节, 可以通过 npm help json 获取文档. 注意 大多数字段都是可选的.
你现在可以在你的顶级目录中通过运行npm install 来安装你的新的npm包了. 如果一切顺利的话, 应该可以简单的加载你的扩展 var notify = require('你的包名');. 一个比较有用的命令式 npm link 通过这个命令你可以创建一个到你开发目录的链接,当你的代码发生变化时不必每次都去安装/卸载.
假设你写了一个很酷的扩展, 你可能想要在中央npm库发布到网上. 你要先创建一个账户:
$ npm adduser
下一步, 回到你的根目录编码并且运行:
$ npm publish
就是这样, 你的包现在已经可以被任何人通过npm install 你的包名命令来安装了.
编程语言
- 如何快速学会编程 如何快速学会ug编程
- 免费学编程的app 推荐12个免费学编程的好网站
- 电脑怎么编程:电脑怎么编程网咯游戏菜单图标
- 如何写代码新手教学 如何写代码新手教学手机
- 基础编程入门教程视频 基础编程入门教程视频华
- 编程演示:编程演示浦丰投针过程
- 乐高编程加盟 乐高积木编程加盟
- 跟我学plc编程 plc编程自学入门视频教程
- ug编程成航林总 ug编程实战视频
- 孩子学编程的好处和坏处
- 初学者学编程该从哪里开始 新手学编程从哪里入
- 慢走丝编程 慢走丝编程难学吗
- 国内十强少儿编程机构 中国少儿编程机构十强有
- 成人计算机速成培训班 成人计算机速成培训班办
- 孩子学编程网上课程哪家好 儿童学编程比较好的
- 代码编程教学入门软件 代码编程教程