SWIG與nodejs入門
- 2020 年 4 月 1 日
- 筆記
前言
Javascipt是一種基於原型的腳本語言。它是動態的,弱類型的語言。它可以說是最流行的Web開發語言。Javascript已經超越了基於瀏覽器的腳本語言,並且與node.js一起,它也被用作後端開發語言。
SWIG Javascript目前支援JavascriptCore,Safari / Webkit使用的Javascript引擎,以及Chromium和node.js使用的v8。
運行 SWIG
假設您像下面這樣,定義了一個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
創建 node.js 擴展
對於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")
在例子
部分中給出了更詳細的解釋。
問題
- 'module' 對免沒有'script_main'屬性 當gyp作為分發包安裝時會發生此錯誤。它似乎已經過時了。刪除它可以解決問題。
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();