Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
861 lines (768 sloc) 25.6 KB
# Generate nodejs binding & build
#
# This is a code generator built using the iMatix GSL code generation
# language. See https://github.com/zeromq/gsl for details.
#
# Copyright (c) the Contributors as noted in the AUTHORS file.
# This file is part of zproject.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
register_target ("nodejs", "Node.js binding")
# Target provides name space isolation for its functions
function target_nodejs
.macro generate_binding
.output "$(topdir)/.gitignore"
node_modules
build
binding.Makefile
*.mk
out/
Makefile
logs
*.log
npm-debug.log*
.for project.use where !optional
$(use.project)/
.endfor
.if !file.exists ("$(topdir)/.prebuildrc")
.output "$(topdir)/.prebuildrc"
prebuild[] = 4.2.4
prebuild[] = 5.6.0
.else
. echo "NOT regenerating an existing $(topdir)/.prebuildrc file; you might want to move yours out of the way and re-generate the project again to get updated settings"
.endif
.if !file.exists ("$(topdir)/index.js")
.output "$(topdir)/index.js"
/*
$(project.name:) exported constants and other initializations
This is a skeleton created by zproject.
You can add hand-written code here.
. for project.license
$(string.trim (license.):block )
. endfor
*/
module.exports = {
$(PROJECT.PREFIX)_WHATEVER: 1
}
.else
. echo "NOT regenerating an existing $(topdir)/index.js boilerplate file; but you probably should not care (unless your licenses changed)"
.endif
.output "$(topdir)/build.sh"
#! /bin/bash
#
# Builds $(project.name:c).node package from a fresh git clone
#
$(project.GENERATED_WARNING_HEADER:)
#
set -e # exit on any error
FORCE=0
VERBOSE=0
QUIET="--quiet"
LOGLEVEL="--loglevel=error"
for ARG in $*; do
if [ "$ARG" == "--help" -o "$ARG" == "-h" ]; then
echo "build.sh"
echo " --help / -h This help"
echo " --force / -f Force full rebuild"
echo " --verbose / -v Show build output"
echo " --xverbose / -x Extra verbose"
exit
elif [ "$ARG" == "--force" -o "$ARG" == "-f" ]; then
FORCE=1
elif [ "$ARG" == "--verbose" -o "$ARG" == "-v" ]; then
VERBOSE=1
QUIET=""
LOGLEVEL=""
elif [ "$ARG" == "--xverbose" -o "$ARG" == "-x" ]; then
VERBOSE=1
QUIET=""
LOGLEVEL="--loglevel=verbose"
set -x
fi
done
BUILD_ROOT=`pwd`
cd ../../..
# Note: here we go to parent directory that contains current project,
# so the checkout is nearby, same as expected for usual developer work
.for project.use where !optional & defined (use.repository)
# Check dependent projects
if [ ! -d $(use.project) ]; then
echo "I: cloning $(use.repository) into `pwd`/$(use.project)..."
.# TODO: Should there be a use of "release" (git branch) like elsewhere?
git clone $QUIET $(use.repository) || exit
fi
if [ ! -f $(use.project)/builds/gyp/project.gyp ]; then
echo "E: `pwd`/$(use.project) out of date (builds/gyp/project.gyp missing)" >&2
exit 1
fi
.endfor
# Check Node.js dependencies
cd $BUILD_ROOT
echo "I: checking Node.js dependencies..."
failed=0
set +e
for package in node-ninja bindings nan prebuild; do
npm list --depth 1 $package > /dev/null 2>&1
if [ $? -eq 1 ]; then
npm list --global --depth 1 $package > /dev/null 2>&1
if [ $? -eq 1 ]; then
echo "E: $package isn't installed, run 'npm install [-g] $package'"
failed=1
fi
fi
done
test $failed -eq 0 || exit
set -e
# Calculate how many compiles we can do in parallel
export JOBS=$\([[ $\(uname) = 'Darwin' ]] \\
&& sysctl -n hw.logicalcpu_max \\
|| lscpu -p | egrep -v '^#' | wc -l)
# Build the binding using node-ninja directly, not prebuild
echo "I: building Node.js binding:"
node-ninja configure
node-ninja build
.close
.chmod_x ("$(topdir)/build.sh")
.output "$(topdir)/binding.gyp"
$(project.GENERATED_WARNING_HEADER:)
# GYP file for $(project.name:) Node.js binding
{
'targets': [
{
'target_name': '$(project.name)',
'sources': [
. for project.use where !optional
.# Note: the file.exists() paths are relative to current project.xml during zproject regen
. if file.exists ("../$(use.project)/$(topdir)/binding.cc")
'../../../$(use.project)/$(topdir)/binding.cc',
. else
. if !file.exists ("../$(use.project)")
. abort "E: please checkout $(use.project) into ../../../$(use.project)"
. endif
. endif
. endfor
'binding.cc'
],
'include_dirs': [
"<!(node -e \\"require('nan')\\")",
. for project.use where !optional
'../../../$(use.project)/include',
. endfor
'../../include'
],
'conditions': [
[ 'OS=="win"', {
'defines': [
.for project.use where !optional
'$(USE.PREFIX)_STATIC',
.endfor
'$(PROJECT.PREFIX)_STATIC'
],
'libraries': [
'ws2_32',
'advapi32',
'iphlpapi',
'Rpcrt4'
]
}],
[ 'OS=="mac"', {
}],
[ 'OS=="linux"', {
'xcode_settings': {
'OTHER_CFLAGS': [
'-fPIC'
],
},
'libraries': [
'-lpthread'
]
}],
],
'dependencies': [
'../../builds/gyp/project.gyp:$(project.libname)'
]
}
]
}
.output "$(topdir)/package.json"
{
"name": "$(project.name)",
"version": "$(nodejs_version?'0.0.1')",
"description": "$(project.description:)",
"scripts": {
"install": "prebuild --install",
"test": "echo \\"Error: no test specified\\" && exit 1",
"rebuild": "prebuild --compile",
"prebuild": "prebuild --strip --verbose"
},
"main": "index",
"author": "See AUTHORS",
"license": "MPL-2.0",
"gypfile": true,
"repository": {
"type": "git",
"url": "$(nodejs_repo?'')"
},
"dependencies": {
"bindings": "^1.2.1",
"nan": "^2.2.0",
"node-ninja": "^1.0.1",
"prebuild": "^3.0.3"
}
}
.
.output "$(topdir)/binding.h"
/* =========================================================================
$(project.name:) Node.js binding header file
. for project.license
$(string.trim (license.):block )
. endfor
$(project.GENERATED_WARNING_HEADER:)
=========================================================================
*/
#ifndef $(PROJECT.NAME:C)_BINDING_H_INCLUDED
#define $(PROJECT.NAME:C)_BINDING_H_INCLUDED
#define $(PROJECT.PREFIX)_BUILD_DRAFT_API
. for project.use where !optional
. if file.exists ("../$(use.project)/$(topdir)/binding.h")
#include "../../../$(use.project)/$(topdir)/binding.h"
. else
. if !file.exists ("../$(use.project)")
. abort "E: please checkout $(use.project) into ../$(use.project)"
. endif
. endif
. endfor
#include "$(project.header)"
#include "nan.h"
using namespace v8;
using namespace Nan;
.for project.class where exported
class $(class.name:Pascal): public Nan::ObjectWrap {
public:
static NAN_MODULE_INIT (Init);
. for class.constructor where name = "new"
explicit $(class.name:Pascal) ($(called:));
explicit $(class.name:Pascal) ($(class.c_name)_t *self);
. else
explicit $(class.name:Pascal) ();
. endfor
. if count (class.constructor)
$(class.c_name)_t *self;
. endif
private:
~$(class.name:Pascal) ();
static Nan::Persistent <Function> &constructor ();
static NAN_METHOD (New);
. for class.destructor
static NAN_METHOD (destroy);
. endfor
. if count (class.constructor)
static NAN_METHOD (defined);
. endif
. for class.method where exported
static NAN_METHOD (_$(method.c_name));
. endfor
};
.endfor
#endif
.output "$(topdir)/binding.cc"
/* =========================================================================
$(project.name:) Node.js binding implementation
. for project.license
$(string.trim (license.):block )
. endfor
$(project.GENERATED_WARNING_HEADER:)
=========================================================================
*/
#include "binding.h"
using namespace v8;
using namespace Nan;
.
.function invoke (method, map_objects)
if my.method.singleton
my.invoke = ""
comma = ""
else
my.invoke = "$(class.c_name)->self"
comma = ", "
endif
for argument
argument.ref = by_reference?? '&'? ''
# These are the types of argument we support so far
if type = "integer" \
| type = "number" \
| type = "size" \
| type = "time" \
| type = "msecs" \
| type = "file_size" \
| type = "boolean" \
| type = "char" \
| type = "real"
my.invoke += "$(comma)($(c_type)) $(ref)$(c_name)"
comma = ", "
elsif type = "string" \
| type = "buffer"
my.invoke += "$(comma)($(c_type))$(ref)$(c_name)"
comma = ", "
elsif type = "format"
my.invoke += "$(comma)\"%s\", $(c_name)"
comma = ", "
elsif type = "nothing"
# Ignore silently
elsif argument.is_object ?= 1 | type = "sockish"
if my.map_objects ?= 1
my.invoke += "$(comma)$(ref)$(c_name)->self"
else
my.invoke += "$(comma)$(ref)$(c_name)"
endif
comma = ", "
else
echo "nodejs: '$(type)', $(class.c_name).$(my.method.c_name).$(argument.c_name)?"
echo "nodejs: unexpected 'invoke ()'"
endif
endfor
return my.invoke
.endfunction
.
.macro resolve_arguments (method, raw)
. for argument
. if type = "integer" \
| type = "number" \
| type = "time" \
| type = "msecs" \
| type = "file_size" \
| type = "boolean" \
| type = "real"
if (info [$(index () - 1)]->IsUndefined ())
return Nan::ThrowTypeError ("method requires a `$(name)`");
//$(c_type) $(c_name); // bjornw typedef - if using c_type, then you get 'int * major' but it needs to be 'int major'. later using the FromJust() returns an int
$(nan_type) $(c_name);
. if type = "boolean"
. my.check = "IsBoolean"
. my.what = "Boolean"
. elsif type = "real"
. my.check = "IsDouble"
. my.what = "number"
. elsif type = "integer" & count (argument.map)
. my.check = "IsNumber"
. my.what = "number or string"
if (info [$(index () - 1)]->IsString ()) {
Nan::Utf8String $(c_name)_utf8 (info [$(index () - 1)].As<String>());
// bjornw: check if we need to remove scope here
char *$(c_name)_name = *$(c_name)_utf8;
for (char *$(c_name)_ptr = $(c_name)_name; *$(c_name)_ptr; $(c_name)_ptr++)
*$(c_name)_ptr = tolower (*$(c_name)_ptr);
. for map
if (streq ($(c_name)_name, "$(map.name)"))
$(c_name) = $(map.value:);
else
. endfor
return Nan::ThrowTypeError ("`$(name)` not a valid string");
}
else
. else
. my.check = "IsNumber"
. my.what = "number"
. endif
if (info [$(index () - 1)]->$(my.check:) ())
{
$(c_name) = Nan::To<$(nan_type:)>(info [$(index () - 1)]).FromJust ();
}
else
return Nan::ThrowTypeError ("`$(name)` must be a $(my.what:)");
. elsif type = "char"
char $(c_name);
if (info [$(index () - 1)]->IsUndefined ())
{
return Nan::ThrowTypeError ("method requires a `$(name)`");
}
else if (!info [$(index () - 1)]->IsString ())
{
return Nan::ThrowTypeError ("`$(name)` must be a string");
}
//else { // bjornw: remove brackets to keep scope
Nan::Utf8String $(c_name)_utf8 (info [$(index () - 1)].As<String>());
if (strlen (*$(c_name)_utf8) != 1)
return Nan::ThrowTypeError ("`$(name)` must be a single character");
$(c_name) = (*$(c_name)_utf8) [0];
//} // bjornw end
. elsif type = "string" | type = "format"
char *$(c_name);
if (info [$(index () - 1)]->IsUndefined ())
. if optional
$(c_name) = NULL;
. else
return Nan::ThrowTypeError ("method requires a `$(name)`");
. endif
else
if (!info [$(index () - 1)]->IsString ())
return Nan::ThrowTypeError ("`$(name)` must be a string");
//else { // bjornw: remove brackets to keep scope
Nan::Utf8String $(c_name)_utf8 (info [$(index () - 1)].As<String>());
$(c_name) = *$(c_name)_utf8;
//} //bjornw end
. elsif type = "buffer"
if (info [$(index () - 1)]->IsUndefined ())
return Nan::ThrowTypeError ("method requires a argument to provide data");
Local<Object> buffer_node = info [$(index () - 1)].As<Object> ();
const byte *$(c_name) = (const byte *) node::Buffer::Data (buffer_node);
. elsif type = "size"
. if my.prev_type ?= "buffer"
size_t $(c_name) = node::Buffer::Length (buffer_node);
. else
if (info [$(index () - 1)]->IsUndefined ())
return Nan::ThrowTypeError ("method requires a `$(name)`");
else
if (!info [$(index () - 1)]->IsNumber ())
return Nan::ThrowTypeError ("`$(name)` must be a number");
$(c_type) $(c_name) = Nan::To<$(nan_type:)>(info [$(index () - 1)]).FromJust ();
. endif
. elsif type = "sockish"
Zsock *$(c_name) = Nan::ObjectWrap::Unwrap<Zsock>(info [$(index () - 1)].As<Object>());
. elsif argument.is_object ?= 1
$(type:Pascal) *$(c_name) = Nan::ObjectWrap::Unwrap<$(type:Pascal)>(info [$(index () - 1)].As<Object>());
. elsif type = "nothing"
. # Do nothing
. else
. echo "nodejs: unhandled '$(type:)', $(class.c_name).$(my.method.c_name).$(argument.c_name)"
// TODO: How do we check $(type)/$(c_type) $(c_name)?
. endif
. my.prev_type = type
. endfor
.endmacro
.
.for project.class where exported
NAN_MODULE_INIT ($(class.name:Pascal)::Init) {
Nan::HandleScope scope;
// Prepare constructor template
Local <FunctionTemplate> tpl = Nan::New <FunctionTemplate> (New);
tpl->SetClassName (Nan::New ("$(class.name:Pascal)").ToLocalChecked ());
tpl->InstanceTemplate ()->SetInternalFieldCount (1);
// Prototypes
. for class.destructor
Nan::SetPrototypeMethod (tpl, "$(destructor.name:Camel)", $(destructor.name));
. endfor
. if count (class.constructor)
Nan::SetPrototypeMethod (tpl, "defined", defined);
. endif
. for class.method where exported
Nan::SetPrototypeMethod (tpl, "$(method.name:Camel)", _$(method.c_name));
. endfor
constructor ().Reset (Nan::GetFunction (tpl).ToLocalChecked ());
Nan::Set (target, Nan::New ("$(class.name:Pascal)").ToLocalChecked (),
Nan::GetFunction (tpl).ToLocalChecked ());
}
. for class.constructor where name = "new"
$(class.name:Pascal)::$(class.name:Pascal) ($(called:)) {
self = $(class.c_name:)_$(c_name) ($(invoke (constructor)));
}
$(class.name:Pascal)::$(class.name:Pascal) ($(class.c_name)_t *self_) {
self = self_;
}
. else
$(class.name:Pascal)::$(class.name:Pascal) () {
}
. endfor
$(class.name:Pascal)::~$(class.name:Pascal) () {
}
NAN_METHOD ($(class.name:Pascal)::New) {
assert (info.IsConstructCall ());
. for class.constructor where name = "new"
. resolve_arguments (constructor)
$(class.name:Pascal) *$(class.c_name) = new $(class.name:Pascal) ($(invoke (constructor, 1)));
. else
$(class.name:Pascal) *$(class.c_name) = new $(class.name:Pascal) ();
. endfor
if ($(class.c_name)) {
$(class.c_name)->Wrap (info.This ());
info.GetReturnValue ().Set (info.This ());
}
}
. for class.destructor
NAN_METHOD ($(class.name:Pascal)::destroy) {
$(class.name:Pascal) *$(class.c_name) = Nan::ObjectWrap::Unwrap <$(class.name:Pascal)> (info.Holder ());
$(class.c_name)_$(destructor.name) (&$(class.c_name)->self);
}
. endfor
. if count (class.constructor)
NAN_METHOD ($(class.name:Pascal)::defined) {
$(class.name:Pascal) *$(class.c_name) = Nan::ObjectWrap::Unwrap <$(class.name:Pascal)> (info.Holder ());
info.GetReturnValue ().Set (Nan::New ($(class.c_name)->self != NULL));
}
. endif
. for class.method where exported
NAN_METHOD ($(class.name:Pascal)::_$(method.c_name)) {
. if !singleton
$(class.name:Pascal) *$(class.c_name) = Nan::ObjectWrap::Unwrap <$(class.name:Pascal)> (info.Holder ());
. endif
. resolve_arguments (method)
. if ->return.type = "integer" \
| ->return.type = "number" \
| ->return.type = "size" \
| ->return.type = "time" \
| ->return.type = "msecs" \
| ->return.type = "file_size" \
| ->return.type = "real"
$(->return.c_type) result = $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
info.GetReturnValue ().Set (Nan::New<Number>(result));
.
. elsif ->return.type = "boolean"
bool result = $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
info.GetReturnValue ().Set (Nan::New<Boolean>(result));
.
. elsif ->return.type = "string"
char *result = (char *) $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
info.GetReturnValue ().Set (Nan::New (result).ToLocalChecked ());
.
. elsif ->return.type = "char"
char result [2] = " ";
result [0] = $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
info.GetReturnValue ().Set (Nan::New (result).ToLocalChecked ());
.
. elsif ->return.type = "buffer"
. if regexp.match ("^\\.(.*)", ->return.size, my.size)
. my.size = "$(class.c_name)_$(my.size) ($(class.c_name)->self)"
. else
. my.size = ->return.size
. endif
const char *result = (const char *) $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
info.GetReturnValue().Set (Nan::CopyBuffer (result, $(my.size)).ToLocalChecked ());
. elsif ->return.is_object ?= 1
$(->return.c_type)result = $(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
$(->return.type:Pascal) *$(->return.type:c)_result = new $(->return.type:Pascal) (result);
if ($(->return.type:c)_result) {
// Don't yet know how to return a new object
// $(->return.type:c)->Wrap (info.This ());
// info.GetReturnValue ().Set (info.This ());
info.GetReturnValue ().Set (Nan::New<Boolean>(true));
}
.
. elsif ->return.type = "nothing"
$(class.c_name)_$(method.c_name) ($(invoke (method, 1)));
.
. else
. echo "nodejs: what do we do with return '$(->return.type:)', $(class.c_name).$(method.c_name)?"
. endif
}
. endfor
Nan::Persistent <Function> &$(class.name:Pascal)::constructor () {
static Nan::Persistent <Function> my_constructor;
return my_constructor;
}
.endfor
extern "C" NAN_MODULE_INIT ($(project.name:c)_initialize)
{
.for project.class where exported
$(class.name:Pascal)::Init (target);
.endfor
}
NODE_MODULE ($(project.name:c), $(project.name:c)_initialize)
.output "$(topdir)/README.md"
# Node.js Binding for $(project.name:)
This is a development kit. Note: this README is generated automatically
by zproject from project.xml. Please DO NOT modify by hand except for test
purposes.
## Prerequisites
### Node.js
* You need Python (v2.7 recommended, v3.x not supported)
* You need (I recommend) nvm and Node.js.
* If your Linux has an existing 'node' command, `sudo apt-get remove node`.
* In every terminal, or .bashrc: `nvm use v5.5.0`
To install the necessary Node tools:
```
sudo apt-get update
sudo apt-get install build-essential libssl-dev
curl https://raw.githubusercontent.com/creationix/nvm/v0.11.1/install.sh | bash
# close terminal, re-open
nvm ls-remote
nvm install v5.5.0
npm install -g nan
npm install -g node-ninja
npm install -g prebuild
npm install -g bindings
```
To build:
```
mkdir -p $HOME/temp
cd $HOME/temp
git clone https://github.com/zeromq/$(project.name:c)
cd $(project.name:c)/bindings/nodejs
# Clones dependencies, builds everything
\./build.sh
```
## API
This is a wrapping of the native C $(project.libname) library. See binding.cc for the code.
.function args (method)
my.args = ""
comma = ""
for argument
if type = "integer" \
| type = "number" \
| type = "real" \
| type = "time" \
| type = "msecs" \
| type = "file_size"
my.args += "$(comma)Number"
elsif type = "boolean"
my.args += "$(comma)Boolean"
elsif type = "char" \
| type = "string" \
| type = "format" \
| type = "buffer"
my.args += "$(comma)String"
elsif type = "sockish"
my.args += "$(comma)Zsock"
elsif argument.is_object ?= 1
my.args += "$(comma)$(type:Pascal)"
endif
comma = ", "
endfor
return my.args
.endfunction
.
.for project.class where exported
### The $(class.name:Pascal) class - $(class.description:)
Constructor:
```
var $(project.prefix) = require ('bindings')('$(project.name:c)')
. for class.constructor where name = "new"
var my_$(class.name:c) = new $(project.prefix).$(class.name:Pascal) ($(args (constructor)))
. else
var my_$(class.name:c) = new $(project.prefix).$(class.name:Pascal) ()
. endfor
```
. for class.destructor
You *must* call the destructor on every $(class.name:Pascal) instance:
```
my_$(class.name:c).$(destructor.name:Camel) ()
```
. endfor
. for class.method where exported
. if first ()
Methods:
. endif
```
. if count (method.return)
. if method.return.is_object ?= 1 & $(->return.is_object)
$(->return.type:Pascal) \
. else
$(->return.type:) \
. endif
. endif
my_$(class.name:c).$(method.name:Camel) ($(args (method)))
```
$(method.description?'':)
. endfor
.endfor
.endmacro
function resolve_method (method)
my.method.called = ""
my.method.exported = 1
comma = ""
for argument
# These are the types of argument we support so far
if type = "integer" \
| type = "number" \
| type = "size" \
| type = "time" \
| type = "msecs" \
| type = "file_size" \
| type = "boolean" \
| type = "char" \
| type = "real"
my.method.called += "$(comma)$(c_type) $(c_name)"
comma = ", "
# Get NAN types for integer casting
if type = "integer"
argument.nan_type = "int"
elsif type = "number"
if size = 1 | size = 2 | size = 4
argument.nan_type = "uint32_t"
else
argument.nan_type = "int64_t"
endif
elsif type = "size" \
| type = "time" \
| type = "msecs" \
| type = "file_size"
argument.nan_type = "int64_t"
elsif type = "boolean"
argument.nan_type = "bool"
elsif type = "real"
argument.nan_type = "double"
endif
elsif type = "format" \
| type = "string" \
| type = "buffer"
my.method.called += "$(comma)$(c_type)$(c_name)"
comma = ", "
elsif type = "sockish"
my.method.called += "$(comma)zsock_t *$(c_name)"
comma = ", "
elsif type = "nothing" \
| destructor_self ?= 1
# Ignore silently
elsif count (project.class, class.c_name = argument.type) \
| count (project->dependencies.class, class.c_name = argument.type)
my.method.called += "$(comma)$(c_type)$(c_name)"
comma = ", "
argument.is_object = 1
else
my.method.exported = 0
# echo "nodejs: can't do '$(type)', $(class.c_name).$(my.method.c_name).$(argument.c_name)"
endif
else
my.method.called += "void"
endfor
# Check if method return is something we know about
if ->return.type = "integer" \
| ->return.type = "number" \
| ->return.type = "size" \
| ->return.type = "time" \
| ->return.type = "msecs" \
| ->return.type = "file_size" \
| ->return.type = "real" \
| ->return.type = "boolean" \
| ->return.type = "string" \
| ->return.type = "char" \
| ->return.type = "buffer" \
| ->return.type = "nothing"
# Good stuff, we know how to return these
elsif count (project.class, class.c_name = my.method->return.type) \
| count (project->dependencies.class, class.c_name = my.method->return.type)
my.method->return.is_object = 1
else
# echo "Suppress $(class.name).$(my.method.name)"
my.method.exported = 0
endif
endfunction
# We always need the gyp target
assume_target ("gyp")
project.topdir = "bindings/nodejs"
directory.create (project.topdir)
for project.class
if defined (class.api) & scope = "public"
class.exported = 1
for constructor
resolve_method (constructor)
if !constructor.exported & constructor.name = "new"
# echo "Suppress $(class.name)"
class.exported = 0
endif
endfor
if class.exported
for destructor
resolve_method (destructor)
endfor
for method
resolve_method (method)
endfor
endif
else
class.exported = 0
endif
endfor
generate_binding ()
endfunction