Javascipt是一种基于原型的脚本语言。它是动态的,弱类型的语言。它可以说是最流行的Web开发语言。Javascript已经超越了基于浏览器的脚本语言,并且与node.js一起,它也被用作后端开发语言。
SWIG Javascript目前支持JavascriptCore,Safari / Webkit使用的Javascript引擎,以及Chromium和node.js使用的v8。
假设您像下面这样,定义了一个SWIG模块:
%module example
%{
#include "example.h"
%}
int gcd(int x, int y);
extern double Foo;
要构建Javascript模块,请使用 -javascript
选项和所希望的目标引擎如:-jsc
,-v8
或-node
运行SWIG。node
生成器基本上委托给v8
生成器并添加一些必要的预处理器定义。
$ swig -javascript -jsc example.i
如果构建C ++扩展,请添加-c ++选项:
$ swig -c++ -javascript -jsc example.i
SWIG生成的V8代码应适用于从3.11.10到3.29.14及更高版本的大多数版本。 大于等于 4.3.0的 V8 API头定义了SWIG用于决定其正在编译的V8版本的常量。小于 4.3的版本,在运行 SWIG时,你要指定V8的版本。版本号是一个16进制的常量,但是常量被读作十进制数字对。如 V8 3.25.30使用常量 0x032530。这种模式不能表达超过 99的数字,但此常量仅在V8版本小于 4.3.0时才使用。并且目前没有任何 V8版本超过了 99。例如:
$ swig -c++ -javascript -v8 -DV8_VERSION=0x032530 example.i
如果你的目标 V8 版本直超过 4.3.0,你应该像下面这样运行 swig:
$ swig -c++ -javascript -v8 example.i
它将创建一个 名为 example_wrap.c 或 example_wrap.cxx 的 C/C++ 文件。产生的 C 源文件包括许多需要被编译底层wapper并与剩下的C/C++应用链接到一起生成一个扩展模块。
wraper文件的名子来自于输入文件。例如, 如果输入文件是 example.i,那么wraper文件的名子就是example_wrap.c。如果要改变它,你可以使用 -o 选项。wrapper模块将导出一个必须被调用的函数,以便将它注册到 javascript解释器中。例如,如果你的模块命名为 example,那么对于 JavascriptCore 对应的初始化函数应该如下:
bool example_initialize(JSGlobalContextRef context, JSObjectRef *exports)
对于 V8
void example_initialize(v8::Handle<v8::Object> exports)
注意: V8使用C ++ API,因此,生成的模块必须编译为C ++
对于测试和例子的配置当前仅支持 Linux和Mac,而不支持 MinGW(Windows)。
默认解释器是node.js,因为它在所有平台上都可用并且使用方便。
使用JavascriptCore运行示例需要安装libjavascriptcoregtk-1.0,例如,在Ubuntu下安装
$ sudo apt-get install libjavascriptcoregtk-1.0-dev
使用V8运行需要libv8:
$ sudo apt-get install libv8-dev
可以使用示例运行
$ make check-javascript-examples ENGINE=jsc
ENGINE可以是node,jsc或v8。
测试套件可以使用
$ make check-javascript-test-suite ENGINE=jsc
您可以指定用于运行示例和测试的特定V8版本
$ make check-javascript-examples V8_VERSION=0x032530 ENGINE=v8
对于Mac和Windows用户可以下载安装包安装node.js。对于Linux用户,你即可以通过 build 源码安装它,也可以通过包安装。
由于v8是用C ++编写的,并且作为C ++库,因此使用与构建v8相同的编译器标志来编译模块至关重要。为了简化操作,node.js提供了一个名为node-gyp的构建工具。
你必须使用npm安装它:
sudo npm install -g node-gyp
node-gyp需要一个名为binding.gyp的配置文件,该文件基本上是JSON格式,并且符合与Google的构建工具gyp一样的格式
binding.gyp:
{
"targets": [
{
"target_name": "example",
"sources": [ "example.cxx", "example_wrap.cxx" ]
}
]
}
首先使用SWIG创建包装器:
$ swig -javascript -node -c++ example.i
然后运行node-gyp build来实际创建模块:
$ node-gyp build
这将创建一个包含Native模块的build文件夹。要使用扩展程序,您需要在Javascript源文件中“require”它:
require("./build/Release/example")
在例子
部分中给出了更详细的解释。
sudo apt-get remove gyp
这里展示一些基本例子和更多的细节:
/* File : example.i */
%module example
%inline %{
extern int gcd(int x, int y);
extern double Foo;
%}
要使其node扩展,必须创建binding.gyp:
{
"targets": [
{
"target_name": "example",
"sources": [ "example.cxx", "example_wrap.cxx" ]
}
]
}
然后node-gyp用于构建扩展:
$ node-gyp configure build
从'nodejs`应用程序将像这样使用扩展:
// import the extension via require
var example = require("./build/Release/example");
// calling the global method
var x = 42;
var y = 105;
var g = example.gcd(x, y);
// Accessing the global variable
var f = example.Foo;
example.Foo = 3.1415926;
首先,加载先前build的扩展example 模块。模块中的全局方法和变量是有效的。
常见的示例类定义了三个类:Shape,Circle和Square:
class Shape {
public:
Shape() {
nshapes++;
}
virtual ~Shape() {
nshapes--;
}
double x, y;
void move(double dx, double dy);
virtual double area(void) = 0;
virtual double perimeter(void) = 0;
static int nshapes;
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double r) : radius(r) { }
virtual double area(void);
virtual double perimeter(void);
};
class Square : public Shape {
private:
double width;
public:
Square(double w) : width(w) { }
virtual double area(void);
virtual double perimeter(void);
};
Circle和Square继承自Shape。Shape具有静态变量nshapes, move
函数不能被重载(非虚函数),并且有两个抽象函数area
和 perimeter
(纯虚函数)必须由子类重载。
nodejs扩展的build方式与simple示例相同。
在Javascript中,它可以使用如下:
var example = require("./build/Release/example");
// local aliases for convenience
var Shape = example.Shape;
var Circle = example.Circle;
var Square = example.Square;
// creating new instances using the 'new' operator
var c = new Circle(10);
var s = new Square(10);
// accessing a static member
Shape.nshapes;
// accessing member variables
c.x = 20;
c.y = 30;
s.x = -10;
s.y = 5;
// calling some methods
c.area();
c.perimeter();
s.area();
s.perimeter();
// instantiation of Shape is not permitted
new Shape();