diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa0b1925c..78f1b33dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,6 +98,14 @@ jobs: ENGINE: node VER: '18' CPPSTD: c++14 + - SWIGLANG: javascript + ENGINE: napi + VER: '14' + CPPSTD: c++11 + - SWIGLANG: javascript + ENGINE: napi + VER: '18' + CPPSTD: c++14 - SWIGLANG: javascript ENGINE: jsc VER: '4.0' diff --git a/.gitignore b/.gitignore index 56c4ad819..38c3bfa9b 100644 --- a/.gitignore +++ b/.gitignore @@ -157,6 +157,7 @@ Examples/java/doxygen/javadocs # Javascript Examples/test-suite/javascript/*/ *.gyp +!Examples/test-suite/javascript/node_template # Lua Examples/lua/dual/dual diff --git a/CHANGES.current b/CHANGES.current index 2a05dea09..650316cc8 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,10 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.2.0 (in progress) =========================== +2023-06-27: mmomtchev + [Javascript] #2545 New Javascript generator targeting the Node.js + binary stable ABI Node-API. + 2023-06-27: olly [Java] Completely remove pragmas which were deprecated in 2002 and have triggered an error since SWIG 2.0: diff --git a/Doc/Manual/Javascript.html b/Doc/Manual/Javascript.html index c4545ecff..6289a0bdf 100644 --- a/Doc/Manual/Javascript.html +++ b/Doc/Manual/Javascript.html @@ -79,7 +79,7 @@ With node-webkit there is int gcd(int x, int y); extern double Foo; -
To build a Javascript module, run SWIG using the -javascript
option and a desired target engine -jsc
, -v8
, or -node
. The generator for node
is essentially delegating to the v8
generator and adds some necessary preprocessor definitions.
To build a Javascript module, run SWIG using the -javascript
option and a desired target engine -jsc
, -v8
, -node
or -napi
. -v8
allows for interfacing with a raw embedded version of V8. In this case, it is up to the user to implement a binary module loading protocol. There are two generators supporting Node.js. The older generator for node
is essentially delegating to the v8
generator and adds some necessary preprocessor definitions. The more recent -napi
generator produces node-addon-api
that interfaces to Node.js through Node-API. The V8 generator is more mature, while the Node-API generator offers a number of advantages such as binary stable ABI allowing for publishing of universal binary modules on npm, Electron support and automatic multi-threading.
$ swig -javascript -jsc example.i@@ -92,6 +92,10 @@ $ swig -c++ -javascript -jsc example.i
The V8 code that SWIG generates requires at least V8 5.0. Keep in mind that this is theV8 version, not Node.js. To give some perspective, Node.js v6.0 uses V8 5.0, v12.0 - 7.4, v14.0 - 8.1...
+The Node-API code that SWIG generates requires Node-API version 6. +This Node-API is available starting from Node.js v10.20 on the v10.x branch, +Node.js v12.17 on the v12.x branch and all versions starting from v14.0.
+To generate code for V8, you would run swig like so:
@@ -127,12 +131,17 @@ $ sudo apt-get install libjavascriptcoregtk-1.0-dev
$ sudo apt-get install libv8-dev
Running with Node-API requires node-addon-api
:
+$ sudo npm install -g node-addon-api+
Examples can be run using
$ make check-javascript-examples ENGINE=jsc
ENGINE
can be node
, jsc
, or v8
.
ENGINE
can be node
, jsc
, v8
, or napi
.
The test-suite can be run using
@@ -150,15 +159,15 @@ $ make check-javascript-examples V8_VERSION=0x032530 ENGINE=v8
At the moment, the Javascript generators pass all tests syntactically, i.e., the generated source code compiles. However, there are still remaining runtime issues.
Default optional arguments do not work for all targeted interpreters
Default optional arguments do not work for all targeted interpreters except Node-API
Multiple output arguments do not work for JSC
C89 incompatibility: the JSC generator might still generate C89 violating code
long long
is not supported
long long
is not supported except with Node-API
Javascript callbacks are not supported
instanceOf
does not work under JSC
The primary development environment has been Linux (Ubuntu 12.04). Windows and Mac OS X have been tested sporadically. Therefore, the generators might have more issues on those platforms. Please report back any problem you observe to help us improving this module quickly.
+The primary development environment has been Linux (Ubuntu 22.04). Windows and Mac OS X have been tested sporadically. Therefore, the generators might have more issues on those platforms. Please report back any problem you observe to help us improving this module quickly.
A more detailed explanation is given in the Examples section.
-yeoman
to generate a Node-API skeletonIf targeting Node-API, the easiest way to bootstrap a project is by using the yeoman
generator:
+$ sudo npm install -g yo +$ sudo npm install -g generator-napi-module +$ mkdir example +$ cd example +$ yo napi-module # the choice of template is irrelevant, SWIG will replace the C++ code +$ npm install node-addon-api@latest # the yeoman version is outdated +$ swig -javascript -napi -c++ -o src/example.cc example.i +$ node-gyp configure +$ node-gyp build ++
There is also the node-magickwand
project that can be used as a tutorial for building and publishing a complex C++ library to
+ npm as a ready-to-use real-world binary module.
The Javascript module is implemented in Source/Modules/javascript.cxx
. It dispatches the code generation to a JSEmitter
instance, V8Emitter
or JSCEmitter
. Additionally there are some helpers: Template
, for templated code generation, and JSEmitterState
, which is used to manage state information during AST traversal. This rough map shall make it easier to find a way through this huge source file:
The Javascript module is implemented in Source/Modules/javascript.cxx
. It dispatches the code generation to a JSEmitter
instance, V8Emitter
, JSCEmitter
or NAPIEmitter
. Additionally there are some helpers: Template
, for templated code generation, and JSEmitterState
, which is used to manage state information during AST traversal. This rough map shall make it easier to find a way through this huge source file:
// module wide defines @@ -629,6 +656,7 @@ class JSEmitter { ... }; JSEmitter *swig_javascript_create_JSCEmitter(); JSEmitter *swig_javascript_create_V8Emitter(); +JSEmitter *swig_javascript_create_NAPIEmitter(); // ############################### // # Javascript module @@ -706,7 +734,7 @@ Template::Template(const String *code_) { ... }28.5.2 Code Templates
-All generated code is created on the basis of code templates. The templates for JavascriptCore can be found in
+Lib/javascript/jsc/javascriptcode.swg
, for v8 inLib/javascript/v8/javascriptcode.swg
.All generated code is created on the basis of code templates. The templates for JavascriptCore can be found in
Lib/javascript/jsc/javascriptcode.swg
, for v8 inLib/javascript/v8/javascriptcode.swg
and for Node-API inLib/javascript/napi.javascriptcode.swg
.To track the originating code template for generated code you can run
+@@ -985,5 +1013,28 @@ if(js_exception) }28.5.6 Handling Exceptions in Node-API
+Node-API is the only generator that provides fully automatic conversion of C++ exceptions to JavaScript exceptions when building with C++ exceptions enabled in `binding.gyp`:
++++'conditions': [ + ['OS=="mac"', + { + 'xcode_settings': { + 'GCC_ENABLE_CPP_RTTI': 'YES', + 'GCC_ENABLE_CPP_EXCEPTIONS' : 'YES' + } + } + ], + ['OS=="linux" or OS=="freebsd" or OS=="openbsd" or OS=="solaris"', + { + 'cflags!': [ '-fno-exceptions' ], + 'cflags_cc!': [ '-fno-exceptions', '-fno-rtti' ] + } + ] +] ++In this case, nothing else is needed for the C++ exceptions to be passed to JavaScript.