build,test: make building addon tests less fragile

* Get rid of recursive `make` when building the node binary.  An earlier
  commit makes GYP write out rules that we can use for proper dependency
  tracking.

* Use module name 'binding' in addons.md and addons-napi/*/binding.gyp.
  This massively simplifies the logic for generating the build rules.

* Check in auto-generated add-on tests from `doc/api/addons.md`.  The
  files change rarely and generating them dynamically causes no end of
  race conditions and special-casing during the build.

PR-URL: https://github.com/nodejs/node/pull/17407
Reviewed-By: Richard Lau <riclau@uk.ibm.com>
This commit is contained in:
Ben Noordhuis 2018-01-20 01:00:34 +01:00 committed by Ruben Bridgewater
parent c6682636be
commit d9b59def72
No known key found for this signature in database
GPG Key ID: F07496B3EB3C1762
95 changed files with 917 additions and 301 deletions

1
.gitignore vendored
View File

@ -74,7 +74,6 @@ ipch/
/npm.wxs /npm.wxs
/tools/msvs/npm.wixobj /tools/msvs/npm.wixobj
/tools/msvs/genfiles/ /tools/msvs/genfiles/
/test/addons/??_*/
email.md email.md
deps/v8-* deps/v8-*
deps/icu deps/icu

262
Makefile
View File

@ -1,3 +1,4 @@
-include .deps # Generated by GYP.
-include config.mk -include config.mk
BUILDTYPE ?= Release BUILDTYPE ?= Release
@ -65,9 +66,9 @@ V ?= 1
# BUILDTYPE=Debug builds both release and debug builds. If you want to compile # BUILDTYPE=Debug builds both release and debug builds. If you want to compile
# just the debug build, run `make -C out BUILDTYPE=Debug` instead. # just the debug build, run `make -C out BUILDTYPE=Debug` instead.
ifeq ($(BUILDTYPE),Release) ifeq ($(BUILDTYPE),Release)
all: out/Makefile $(NODE_EXE) ## Default target, builds node in out/Release/node. all: $(NODE_EXE) ## Default target, builds node in out/Release/node.
else else
all: out/Makefile $(NODE_EXE) $(NODE_G_EXE) all: $(NODE_EXE) $(NODE_G_EXE)
endif endif
.PHONY: help .PHONY: help
@ -77,32 +78,24 @@ help: ## Print help for targets with comments.
@grep -E '^[a-zA-Z0-9._-]+:.*?## .*$$' Makefile | sort | \ @grep -E '^[a-zA-Z0-9._-]+:.*?## .*$$' Makefile | sort | \
awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}' awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-15s\033[0m %s\n", $$1, $$2}'
# The .PHONY is needed to ensure that we recursively use the out/Makefile $(NODE_EXE): out/Release/node
# to check for changes. ln -fs $< $@
.PHONY: $(NODE_EXE) $(NODE_G_EXE)
# The -r/-L check stops it recreating the link if it is already in place, $(NODE_G_EXE): out/Debug/node
# otherwise $(NODE_EXE) being a .PHONY target means it is always re-run. ln -fs $< $@
# Without the check there is a race condition between the link being deleted
# and recreated which can break the addons build when running test-ci out/Release/node: out/Makefile $(ALL_DEPS)
# See comments on the build-addons target for some more info
$(NODE_EXE): config.gypi out/Makefile
$(MAKE) -C out BUILDTYPE=Release V=$(V) $(MAKE) -C out BUILDTYPE=Release V=$(V)
if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Release/$(NODE_EXE) $@; fi
$(NODE_G_EXE): config.gypi out/Makefile out/Debug/node: out/Makefile $(ALL_DEPS)
$(MAKE) -C out BUILDTYPE=Debug V=$(V) $(MAKE) -C out BUILDTYPE=Debug V=$(V)
if [ ! -r $@ -o ! -L $@ ]; then ln -fs out/Debug/$(NODE_EXE) $@; fi
out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp \ out/Makefile .deps: deps/uv/uv.gyp deps/http_parser/http_parser.gyp \
deps/zlib/zlib.gyp deps/v8/gypfiles/toolchain.gypi \ deps/zlib/zlib.gyp deps/v8/gypfiles/toolchain.gypi \
deps/v8/gypfiles/features.gypi deps/v8/src/v8.gyp node.gyp \ deps/v8/gypfiles/features.gypi deps/v8/src/v8.gyp node.gyp \
config.gypi common.gypi config.gypi
$(PYTHON) tools/gyp_node.py -f make $(PYTHON) tools/gyp_node.py -f make
config.gypi: configure
$(error Missing or stale $@, please run ./$<)
.PHONY: install .PHONY: install
install: all ## Installs node into $PREFIX (default=/usr/local). install: all ## Installs node into $PREFIX (default=/usr/local).
$(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)' $(PYTHON) tools/install.py $@ '$(DESTDIR)' '$(PREFIX)'
@ -232,9 +225,7 @@ v8:
.PHONY: test .PHONY: test
# This does not run tests of third-party libraries inside deps. # This does not run tests of third-party libraries inside deps.
test: all ## Runs default tests, linters, and builds docs. test: all build-addons ## Runs default tests, linters, and builds docs.
$(MAKE) -s build-addons
$(MAKE) -s build-addons-napi
$(MAKE) -s doc-only $(MAKE) -s doc-only
$(MAKE) -s lint $(MAKE) -s lint
$(MAKE) -s cctest $(MAKE) -s cctest
@ -244,18 +235,14 @@ test: all ## Runs default tests, linters, and builds docs.
$(CI_DOC) $(CI_DOC)
.PHONY: test-only .PHONY: test-only
test-only: all ## For a quick test, does not run linter or build docs. test-only: all build-addons ## For a quick test, does not run linter or build docs.
$(MAKE) build-addons
$(MAKE) build-addons-napi
$(MAKE) cctest $(MAKE) cctest
$(PYTHON) tools/test.py --mode=release -J \ $(PYTHON) tools/test.py --mode=release -J \
$(CI_JS_SUITES) \ $(CI_JS_SUITES) \
$(CI_NATIVE_SUITES) $(CI_NATIVE_SUITES)
# Used by `make coverage-test` # Used by `make coverage-test`
test-cov: all test-cov: all build-addons
$(MAKE) build-addons
$(MAKE) build-addons-napi
# $(MAKE) cctest # $(MAKE) cctest
$(PYTHON) tools/test.py --mode=release -J \ $(PYTHON) tools/test.py --mode=release -J \
$(CI_JS_SUITES) \ $(CI_JS_SUITES) \
@ -271,115 +258,53 @@ test-valgrind: all
test-check-deopts: all test-check-deopts: all
$(PYTHON) tools/test.py --mode=release --check-deopts parallel sequential -J $(PYTHON) tools/test.py --mode=release --check-deopts parallel sequential -J
benchmark/misc/function_call/build/Release/binding.node: all \ ADDON_PREREQS := \
benchmark/misc/function_call/binding.cc \ common.gypi \
benchmark/misc/function_call/binding.gyp config.gypi \
$(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ deps/npm/node_modules/node-gyp/package.json \
--python="$(PYTHON)" \ src/node.h \
--directory="$(shell pwd)/benchmark/misc/function_call" \ src/node_api.h \
--nodedir="$(shell pwd)" src/node_api_types.h \
src/node_buffer.h \
# Implicitly depends on $(NODE_EXE). We don't depend on it explicitly because src/node_object_wrap.h \
# it always triggers a rebuild due to it being a .PHONY rule. See the comment src/node_version.h \
# near the build-addons rule for more background. $(wildcard deps/openssl/openssl/include/openssl/*.h) \
test/gc/build/Release/binding.node: test/gc/binding.cc test/gc/binding.gyp $(wildcard deps/uv/include/*.h) \
$(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp rebuild \ $(wildcard deps/v8/include/*.h) \
--python="$(PYTHON)" \ $(wildcard deps/zlib/*.h) \
--directory="$(shell pwd)/test/gc" \
--nodedir="$(shell pwd)"
DOCBUILDSTAMP_PREREQS = tools/doc/addon-verify.js doc/api/addons.md
ifeq ($(OSTYPE),aix) ifeq ($(OSTYPE),aix)
DOCBUILDSTAMP_PREREQS := $(DOCBUILDSTAMP_PREREQS) out/$(BUILDTYPE)/node.exp ADDON_PREREQS := $(ADDON_PREREQS) out/$(BUILDTYPE)/node.exp
endif endif
test/addons/.docbuildstamp: $(DOCBUILDSTAMP_PREREQS) ADDON_DIRS := \
$(RM) -r test/addons/??_*/ $(dir benchmark/misc/function_call/ test/gc/ \
[ -x $(NODE) ] && $(NODE) $< || node $< $(wildcard test/addons-napi/*/binding.gyp) \
touch $@
ADDONS_BINDING_GYPS := \
$(filter-out test/addons/??_*/binding.gyp, \
$(wildcard test/addons/*/binding.gyp)) $(wildcard test/addons/*/binding.gyp))
ADDONS_BINDING_SOURCES := \ ADDON_FILES := \
$(filter-out test/addons/??_*/*.cc, $(wildcard test/addons/*/*.cc)) \ $(foreach d, $(ADDON_DIRS), $(d)build/$(BUILDTYPE)/binding.node)
$(filter-out test/addons/??_*/*.h, $(wildcard test/addons/*/*.h))
# Implicitly depends on $(NODE_EXE), see the build-addons rule for rationale. NODE_GYP := \
# Depends on node-gyp package.json so that build-addons is (re)executed when env MAKEFLAGS="-j1" \
# node-gyp is updated as part of an npm update. $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp \
test/addons/.buildstamp: config.gypi \ --loglevel="$(LOGLEVEL)" --nodedir="$(CURDIR)" --python="$(PYTHON)"
deps/npm/node_modules/node-gyp/package.json \
$(ADDONS_BINDING_GYPS) $(ADDONS_BINDING_SOURCES) \ define do_addon
deps/uv/include/*.h deps/v8/include/*.h \ $(1)build/Makefile: $(1)binding.gyp common.gypi
src/node.h src/node_buffer.h src/node_object_wrap.h src/node_version.h \ $(NODE_GYP) --directory=$(1) configure
test/addons/.docbuildstamp $(1)build/Release/.buildstamp: $(1)build/Makefile $(2) $(ADDON_PREREQS)
# Cannot use $(wildcard test/addons/*/) here, it's evaluated before $(NODE_GYP) --directory=$(1) build
# embedded addons have been generated from the documentation. @touch $$@
# Ignore folders without binding.gyp $(1)build/Release/binding.node: $(1)build/Release/.buildstamp
# (https://github.com/nodejs/node/issues/14843) endef
@for dirname in test/addons/*/; do \
if [ ! -f "$$PWD/$${dirname}binding.gyp" ]; then \ $(foreach x, $(ADDON_DIRS), \
continue; fi ; \ $(eval $(call do_addon,$(x),$(wildcard $(x)/*.{c,cc,h}))))
printf "\nBuilding addon $$PWD/$$dirname\n" ; \
env MAKEFLAGS="-j1" $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp \
--loglevel=$(LOGLEVEL) rebuild \
--python="$(PYTHON)" \
--directory="$$PWD/$$dirname" \
--nodedir="$$PWD" || exit 1 ; \
done
touch $@
.PHONY: build-addons .PHONY: build-addons
# .buildstamp needs $(NODE_EXE) but cannot depend on it build-addons: $(NODE)
# directly because it calls make recursively. The parent make cannot know @$(MAKE) -s $(ADDON_FILES)
# if the subprocess touched anything so it pessimistically assumes that
# .buildstamp is out of date and need a rebuild.
# Just goes to show that recursive make really is harmful...
# TODO(bnoordhuis) Force rebuild after gyp update.
build-addons: | $(NODE_EXE) test/addons/.buildstamp
ADDONS_NAPI_BINDING_GYPS := \
$(filter-out test/addons-napi/??_*/binding.gyp, \
$(wildcard test/addons-napi/*/binding.gyp))
ADDONS_NAPI_BINDING_SOURCES := \
$(filter-out test/addons-napi/??_*/*.cc, $(wildcard test/addons-napi/*/*.cc)) \
$(filter-out test/addons-napi/??_*/*.h, $(wildcard test/addons-napi/*/*.h))
# Implicitly depends on $(NODE_EXE), see the build-addons-napi rule for rationale.
test/addons-napi/.buildstamp: config.gypi \
deps/npm/node_modules/node-gyp/package.json \
$(ADDONS_NAPI_BINDING_GYPS) $(ADDONS_NAPI_BINDING_SOURCES) \
deps/uv/include/*.h deps/v8/include/*.h \
src/node.h src/node_buffer.h src/node_object_wrap.h src/node_version.h \
src/node_api.h src/node_api_types.h
# Cannot use $(wildcard test/addons-napi/*/) here, it's evaluated before
# embedded addons have been generated from the documentation.
# Ignore folders without binding.gyp
# (https://github.com/nodejs/node/issues/14843)
@for dirname in test/addons-napi/*/; do \
if [ ! -f "$$PWD/$${dirname}binding.gyp" ]; then \
continue; fi ; \
printf "\nBuilding addon $$PWD/$$dirname\n" ; \
env MAKEFLAGS="-j1" $(NODE) deps/npm/node_modules/node-gyp/bin/node-gyp \
--loglevel=$(LOGLEVEL) rebuild \
--python="$(PYTHON)" \
--directory="$$PWD/$$dirname" \
--nodedir="$$PWD" || exit 1 ; \
done
touch $@
.PHONY: build-addons-napi
# .buildstamp needs $(NODE_EXE) but cannot depend on it
# directly because it calls make recursively. The parent make cannot know
# if the subprocess touched anything so it pessimistically assumes that
# .buildstamp is out of date and need a rebuild.
# Just goes to show that recursive make really is harmful...
# TODO(bnoordhuis) Force rebuild after gyp or node-gyp update.
build-addons-napi: | $(NODE_EXE) test/addons-napi/.buildstamp
.PHONY: clear-stalled .PHONY: clear-stalled
clear-stalled: clear-stalled:
@ -398,15 +323,11 @@ test-gc: all test/gc/build/Release/binding.node
test-gc-clean: test-gc-clean:
$(RM) -r test/gc/build $(RM) -r test/gc/build
test-build: | all build-addons build-addons-napi
test-build-addons-napi: all build-addons-napi
.PHONY: test-all .PHONY: test-all
test-all: test-build test/gc/build/Release/binding.node ## Run everything in test/. test-all: test/gc/build/Release/binding.node ## Run everything in test/.
$(PYTHON) tools/test.py --mode=debug,release $(PYTHON) tools/test.py --mode=debug,release
test-all-valgrind: test-build test-all-valgrind: build-addons
$(PYTHON) tools/test.py --mode=debug,release --valgrind $(PYTHON) tools/test.py --mode=debug,release --valgrind
CI_NATIVE_SUITES ?= addons addons-napi CI_NATIVE_SUITES ?= addons addons-napi
@ -417,7 +338,7 @@ CI_DOC := doctool
# Build and test addons without building anything else # Build and test addons without building anything else
# Related CI job: node-test-commit-arm-fanned # Related CI job: node-test-commit-arm-fanned
test-ci-native: LOGLEVEL := info test-ci-native: LOGLEVEL := info
test-ci-native: | test/addons/.buildstamp test/addons-napi/.buildstamp test-ci-native: $(ADDON_FILES)
$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
--mode=release --flaky-tests=$(FLAKY_TESTS) \ --mode=release --flaky-tests=$(FLAKY_TESTS) \
$(TEST_CI_ARGS) $(CI_NATIVE_SUITES) $(TEST_CI_ARGS) $(CI_NATIVE_SUITES)
@ -439,7 +360,7 @@ test-ci-js: | clear-stalled
.PHONY: test-ci .PHONY: test-ci
# Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned # Related CI jobs: most CI tests, excluding node-test-commit-arm-fanned
test-ci: LOGLEVEL := info test-ci: LOGLEVEL := info
test-ci: | clear-stalled build-addons build-addons-napi doc-only test-ci: build-addons | clear-stalled doc-only
out/Release/cctest --gtest_output=tap:cctest.tap out/Release/cctest --gtest_output=tap:cctest.tap
$(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \ $(PYTHON) tools/test.py $(PARALLEL_ARGS) -p tap --logfile test.tap \
--mode=release --flaky-tests=$(FLAKY_TESTS) \ --mode=release --flaky-tests=$(FLAKY_TESTS) \
@ -468,13 +389,13 @@ build-ci:
run-ci: build-ci run-ci: build-ci
$(MAKE) test-ci $(MAKE) test-ci
test-release: test-build test-release: build-addons
$(PYTHON) tools/test.py --mode=release $(PYTHON) tools/test.py --mode=release
test-debug: test-build test-debug: build-addons
$(PYTHON) tools/test.py --mode=debug $(PYTHON) tools/test.py --mode=debug
test-message: test-build test-message: all
$(PYTHON) tools/test.py message $(PYTHON) tools/test.py message
test-simple: | cctest # Depends on 'all'. test-simple: | cctest # Depends on 'all'.
@ -514,23 +435,21 @@ test-npm-publish: $(NODE_EXE)
npm_package_config_publishtest=true $(NODE) deps/npm/test/run.js npm_package_config_publishtest=true $(NODE) deps/npm/test/run.js
.PHONY: test-addons-napi .PHONY: test-addons-napi
test-addons-napi: test-build-addons-napi test-addons-napi: build-addons
$(PYTHON) tools/test.py --mode=release addons-napi $(PYTHON) tools/test.py --mode=release addons-napi
.PHONY: test-addons-napi-clean .PHONY: test-addons-napi-clean
test-addons-napi-clean: test-addons-napi-clean:
$(RM) -r test/addons-napi/*/build $(RM) -r test/addons-napi/*/build
$(RM) test/addons-napi/.buildstamp
.PHONY: test-addons .PHONY: test-addons
test-addons: test-build test-addons-napi test-addons: build-addons
$(PYTHON) tools/test.py --mode=release addons $(PYTHON) tools/test.py --mode=release addons
.PHONY: test-addons-clean .PHONY: test-addons-clean
test-addons-clean: test-addons-clean:
$(RM) -r test/addons/??_*/ $(RM) -r test/addons/??_*/
$(RM) -r test/addons/*/build $(RM) -r test/addons/*/build
$(RM) test/addons/.buildstamp test/addons/.docbuildstamp
$(MAKE) test-addons-napi-clean $(MAKE) test-addons-napi-clean
test-timers: test-timers:
@ -543,9 +462,7 @@ test-timers-clean:
test-async-hooks: test-async-hooks:
$(PYTHON) tools/test.py --mode=release async-hooks $(PYTHON) tools/test.py --mode=release async-hooks
test-with-async-hooks: test-with-async-hooks: build-addons
$(MAKE) build-addons
$(MAKE) build-addons-napi
$(MAKE) cctest $(MAKE) cctest
NODE_TEST_WITH_ASYNC_HOOKS=1 $(PYTHON) tools/test.py --mode=release -J \ NODE_TEST_WITH_ASYNC_HOOKS=1 $(PYTHON) tools/test.py --mode=release -J \
$(CI_JS_SUITES) \ $(CI_JS_SUITES) \
@ -1113,36 +1030,32 @@ lint-js-ci:
jslint-ci: lint-js-ci jslint-ci: lint-js-ci
@echo "Please use lint-js-ci instead of jslint-ci" @echo "Please use lint-js-ci instead of jslint-ci"
LINT_CPP_ADDON_DOC_FILES = $(wildcard test/addons/??_*/*.cc test/addons/??_*/*.h)
LINT_CPP_EXCLUDE ?= LINT_CPP_EXCLUDE ?=
LINT_CPP_EXCLUDE += src/node_root_certs.h LINT_CPP_EXCLUDE += src/node_root_certs.h
LINT_CPP_EXCLUDE += $(LINT_CPP_ADDON_DOC_FILES)
LINT_CPP_EXCLUDE += $(wildcard test/addons-napi/??_*/*.cc test/addons-napi/??_*/*.h)
# These files were copied more or less verbatim from V8. # These files were copied more or less verbatim from V8.
LINT_CPP_EXCLUDE += src/tracing/trace_event.h src/tracing/trace_event_common.h LINT_CPP_EXCLUDE += src/tracing/trace_event.h src/tracing/trace_event_common.h
LINT_CPP_FILES = $(filter-out $(LINT_CPP_EXCLUDE), $(wildcard \ LINT_CPP_FILES := \
benchmark/misc/function_call/binding.cc \ $(filter-out \
src/*.c \ $(LINT_CPP_EXCLUDE), \
src/*.cc \ $(wildcard \
src/*.h \ benchmark/misc/function_call/binding.cc \
src/*/*.c \ src/*.c \
src/*/*.cc \ src/*.cc \
src/*/*.h \ src/*.h \
test/addons/*/*.cc \ src/*/*.c \
test/addons/*/*.h \ src/*/*.cc \
test/cctest/*.cc \ src/*/*.h \
test/cctest/*.h \ test/addons/*/*.cc \
test/addons-napi/*/*.cc \ test/addons/*/*.h \
test/addons-napi/*/*.h \ test/cctest/*.cc \
test/gc/binding.cc \ test/cctest/*.h \
tools/icu/*.cc \ test/addons-napi/*/*.cc \
tools/icu/*.h \ test/addons-napi/*/*.h \
)) test/gc/binding.cc \
tools/icu/*.cc \
# Code blocks don't have newline at the end, tools/icu/*.h \
# and the actual filename is generated so it won't match header guards ))
ADDON_DOC_LINT_FLAGS=-whitespace/ending_newline,-build/header_guard
.PHONY: lint-cpp .PHONY: lint-cpp
# Lints the C++ code with cpplint.py and check-imports.py. # Lints the C++ code with cpplint.py and check-imports.py.
@ -1154,10 +1067,6 @@ tools/.cpplintstamp: $(LINT_CPP_FILES)
@$(PYTHON) tools/check-imports.py @$(PYTHON) tools/check-imports.py
@touch $@ @touch $@
lint-addon-docs: test/addons/.docbuildstamp
@echo "Running C++ linter on addon docs..."
@$(PYTHON) tools/cpplint.py --filter=$(ADDON_DOC_LINT_FLAGS) $(LINT_CPP_ADDON_DOC_FILES)
cpplint: lint-cpp cpplint: lint-cpp
@echo "Please use lint-cpp instead of cpplint" @echo "Please use lint-cpp instead of cpplint"
@ -1168,12 +1077,11 @@ lint: ## Run JS, C++, MD and doc linters.
@EXIT_STATUS=0 ; \ @EXIT_STATUS=0 ; \
$(MAKE) lint-js || EXIT_STATUS=$$? ; \ $(MAKE) lint-js || EXIT_STATUS=$$? ; \
$(MAKE) lint-cpp || EXIT_STATUS=$$? ; \ $(MAKE) lint-cpp || EXIT_STATUS=$$? ; \
$(MAKE) lint-addon-docs || EXIT_STATUS=$$? ; \
exit $$EXIT_STATUS exit $$EXIT_STATUS
CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+ CONFLICT_RE=^>>>>>>> [0-9A-Fa-f]+|^<<<<<<< [A-Za-z]+
# Related CI job: node-test-linter # Related CI job: node-test-linter
lint-ci: lint-js-ci lint-cpp lint-md lint-addon-docs lint-ci: lint-js-ci lint-cpp lint-md
@if ! ( grep -IEqrs "$(CONFLICT_RE)" benchmark deps doc lib src test tools ) \ @if ! ( grep -IEqrs "$(CONFLICT_RE)" benchmark deps doc lib src test tools ) \
&& ! ( find . -maxdepth 1 -type f | xargs grep -IEqs "$(CONFLICT_RE)" ); then \ && ! ( find . -maxdepth 1 -type f | xargs grep -IEqs "$(CONFLICT_RE)" ); then \
exit 0 ; \ exit 0 ; \

View File

@ -1,3 +1,6 @@
<!--
Run `node tools/doc/addon-verify.js` when you change examples in this document.
-->
# C++ Addons # C++ Addons
<!--introduced_in=v0.10.0--> <!--introduced_in=v0.10.0-->
@ -94,12 +97,12 @@ The `module_name` must match the filename of the final binary (excluding
the .node suffix). the .node suffix).
In the `hello.cc` example, then, the initialization function is `init` and the In the `hello.cc` example, then, the initialization function is `init` and the
Addon module name is `addon`. Addon module name is `binding`.
### Building ### Building
Once the source code has been written, it must be compiled into the binary Once the source code has been written, it must be compiled into the binary
`addon.node` file. To do so, create a file called `binding.gyp` in the `binding.node` file. To do so, create a file called `binding.gyp` in the
top-level of the project describing the build configuration of the module top-level of the project describing the build configuration of the module
using a JSON-like format. This file is used by [node-gyp][] -- a tool written using a JSON-like format. This file is used by [node-gyp][] -- a tool written
specifically to compile Node.js Addons. specifically to compile Node.js Addons.
@ -108,7 +111,7 @@ specifically to compile Node.js Addons.
{ {
"targets": [ "targets": [
{ {
"target_name": "addon", "target_name": "binding",
"sources": [ "hello.cc" ] "sources": [ "hello.cc" ]
} }
] ]
@ -128,21 +131,21 @@ generate the appropriate project build files for the current platform. This
will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file will generate either a `Makefile` (on Unix platforms) or a `vcxproj` file
(on Windows) in the `build/` directory. (on Windows) in the `build/` directory.
Next, invoke the `node-gyp build` command to generate the compiled `addon.node` Next, invoke the `node-gyp build` command to generate the compiled
file. This will be put into the `build/Release/` directory. `binding.node` file. This will be put into the `build/Release/` directory.
When using `npm install` to install a Node.js Addon, npm uses its own bundled When using `npm install` to install a Node.js Addon, npm uses its own bundled
version of `node-gyp` to perform this same set of actions, generating a version of `node-gyp` to perform this same set of actions, generating a
compiled version of the Addon for the user's platform on demand. compiled version of the Addon for the user's platform on demand.
Once built, the binary Addon can be used from within Node.js by pointing Once built, the binary Addon can be used from within Node.js by pointing
[`require()`][require] to the built `addon.node` module: [`require()`][require] to the built `binding.node` module:
```js ```js
// hello.js // hello.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
console.log(addon.hello()); console.log(binding.hello());
// Prints: 'world' // Prints: 'world'
``` ```
@ -159,9 +162,9 @@ similar to:
```js ```js
try { try {
return require('./build/Release/addon.node'); return require('./build/Release/binding.node');
} catch (err) { } catch (err) {
return require('./build/Debug/addon.node'); return require('./build/Debug/binding.node');
} }
``` ```
@ -195,9 +198,9 @@ When calling [`require()`][require], the `.node` extension can usually be
omitted and Node.js will still find and initialize the Addon. One caveat, omitted and Node.js will still find and initialize the Addon. One caveat,
however, is that Node.js will first attempt to locate and load modules or however, is that Node.js will first attempt to locate and load modules or
JavaScript files that happen to share the same base name. For instance, if JavaScript files that happen to share the same base name. For instance, if
there is a file `addon.js` in the same directory as the binary `addon.node`, there is a file `binding.js` in the same directory as the binary `binding.node`,
then [`require('addon')`][require] will give precedence to the `addon.js` file then [`require('binding')`][require] will give precedence to the `binding.js`
and load it instead. file and load it instead.
## Native Abstractions for Node.js ## Native Abstractions for Node.js
@ -284,8 +287,8 @@ Each of these examples using the following `binding.gyp` file:
{ {
"targets": [ "targets": [
{ {
"target_name": "addon", "target_name": "binding",
"sources": [ "addon.cc" ] "sources": [ "binding.cc" ]
} }
] ]
} }
@ -295,7 +298,7 @@ In cases where there is more than one `.cc` file, simply add the additional
filename to the `sources` array. For example: filename to the `sources` array. For example:
```json ```json
"sources": ["addon.cc", "myexample.cc"] "sources": ["binding.cc", "myexample.cc"]
``` ```
Once the `binding.gyp` file is ready, the example Addons can be configured and Once the `binding.gyp` file is ready, the example Addons can be configured and
@ -317,7 +320,7 @@ The following example illustrates how to read function arguments passed from
JavaScript and how to return a result: JavaScript and how to return a result:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
namespace demo { namespace demo {
@ -374,9 +377,9 @@ Once compiled, the example Addon can be required and used from within Node.js:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
console.log('This should be eight:', addon.add(3, 5)); console.log('This should be eight:', binding.add(3, 5));
``` ```
@ -387,7 +390,7 @@ function and execute them from there. The following example illustrates how
to invoke such callbacks: to invoke such callbacks:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
namespace demo { namespace demo {
@ -427,9 +430,9 @@ To test it, run the following JavaScript:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
addon((msg) => { binding((msg) => {
console.log(msg); console.log(msg);
// Prints: 'hello world' // Prints: 'hello world'
}); });
@ -444,7 +447,7 @@ illustrated in the following example. An object is created and returned with a
property `msg` that echoes the string passed to `createObject()`: property `msg` that echoes the string passed to `createObject()`:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
namespace demo { namespace demo {
@ -478,10 +481,10 @@ To test it in JavaScript:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
const obj1 = addon('hello'); const obj1 = binding('hello');
const obj2 = addon('world'); const obj2 = binding('world');
console.log(obj1.msg, obj2.msg); console.log(obj1.msg, obj2.msg);
// Prints: 'hello world' // Prints: 'hello world'
``` ```
@ -493,7 +496,7 @@ Another common scenario is creating JavaScript functions that wrap C++
functions and returning those back to JavaScript: functions and returning those back to JavaScript:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
namespace demo { namespace demo {
@ -537,9 +540,9 @@ To test:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
const fn = addon(); const fn = binding();
console.log(fn()); console.log(fn());
// Prints: 'hello world' // Prints: 'hello world'
``` ```
@ -551,7 +554,7 @@ It is also possible to wrap C++ objects/classes in a way that allows new
instances to be created using the JavaScript `new` operator: instances to be created using the JavaScript `new` operator:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
#include "myobject.h" #include "myobject.h"
@ -686,9 +689,9 @@ To build this example, the `myobject.cc` file must be added to the
{ {
"targets": [ "targets": [
{ {
"target_name": "addon", "target_name": "binding",
"sources": [ "sources": [
"addon.cc", "binding.cc",
"myobject.cc" "myobject.cc"
] ]
} }
@ -700,9 +703,9 @@ Test it with:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
const obj = new addon.MyObject(10); const obj = new binding.MyObject(10);
console.log(obj.plusOne()); console.log(obj.plusOne());
// Prints: 11 // Prints: 11
console.log(obj.plusOne()); console.log(obj.plusOne());
@ -717,15 +720,15 @@ Alternatively, it is possible to use a factory pattern to avoid explicitly
creating object instances using the JavaScript `new` operator: creating object instances using the JavaScript `new` operator:
```js ```js
const obj = addon.createObject(); const obj = binding.createObject();
// instead of: // instead of:
// const obj = new addon.Object(); // const obj = new binding.Object();
``` ```
First, the `createObject()` method is implemented in `addon.cc`: First, the `createObject()` method is implemented in `binding.cc`:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
#include "myobject.h" #include "myobject.h"
@ -881,9 +884,9 @@ Once again, to build this example, the `myobject.cc` file must be added to the
{ {
"targets": [ "targets": [
{ {
"target_name": "addon", "target_name": "binding",
"sources": [ "sources": [
"addon.cc", "binding.cc",
"myobject.cc" "myobject.cc"
] ]
} }
@ -895,7 +898,7 @@ Test it with:
```js ```js
// test.js // test.js
const createObject = require('./build/Release/addon'); const createObject = require('./build/Release/binding');
const obj = createObject(10); const obj = createObject(10);
console.log(obj.plusOne()); console.log(obj.plusOne());
@ -923,7 +926,7 @@ wrapped objects around by unwrapping them with the Node.js helper function
that can take two `MyObject` objects as input arguments: that can take two `MyObject` objects as input arguments:
```cpp ```cpp
// addon.cc // binding.cc
#include <node.h> #include <node.h>
#include <node_object_wrap.h> #include <node_object_wrap.h>
#include "myobject.h" #include "myobject.h"
@ -1077,11 +1080,11 @@ Test it with:
```js ```js
// test.js // test.js
const addon = require('./build/Release/addon'); const binding = require('./build/Release/binding');
const obj1 = addon.createObject(10); const obj1 = binding.createObject(10);
const obj2 = addon.createObject(20); const obj2 = binding.createObject(20);
const result = addon.add(obj1, obj2); const result = binding.add(obj1, obj2);
console.log(result); console.log(result);
// Prints: 30 // Prints: 30
@ -1106,10 +1109,10 @@ and a pointer to untyped context data to be passed to that callback.
Callbacks are run in last-in first-out order. Callbacks are run in last-in first-out order.
The following `addon.cc` implements AtExit: The following `binding.cc` implements AtExit:
```cpp ```cpp
// addon.cc // binding.cc
#include <assert.h> #include <assert.h>
#include <stdlib.h> #include <stdlib.h>
#include <node.h> #include <node.h>
@ -1161,7 +1164,7 @@ Test in JavaScript by running:
```js ```js
// test.js // test.js
require('./build/Release/addon'); require('./build/Release/binding');
``` ```
[Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide [Embedder's Guide]: https://github.com/v8/v8/wiki/Embedder's%20Guide

View File

@ -533,14 +533,6 @@
# node_dtrace_ustack.o not supported on mac and linux # node_dtrace_ustack.o not supported on mac and linux
# node_dtrace_provider.o All except OS X. "dtrace -G" is not # node_dtrace_provider.o All except OS X. "dtrace -G" is not
# used on OS X. # used on OS X.
#
# Note that node_dtrace_provider.cc and node_dtrace_ustack.cc do not
# actually exist. They're listed here to trick GYP into linking the
# corresponding object files into the final "node" executable. These
# object files are generated by "dtrace -G" using custom actions
# below, and the GYP-generated Makefiles will properly build them when
# needed.
#
'sources': [ 'src/node_dtrace.cc' ], 'sources': [ 'src/node_dtrace.cc' ],
'conditions': [ 'conditions': [
[ 'OS=="linux"', { [ 'OS=="linux"', {
@ -550,8 +542,8 @@
}], }],
[ 'OS!="mac" and OS!="linux"', { [ 'OS!="mac" and OS!="linux"', {
'sources': [ 'sources': [
'src/node_dtrace_ustack.cc', '<(OBJ_DIR)/<(node_lib_target_name)/src/node_dtrace_provider.o',
'src/node_dtrace_provider.cc', '<(OBJ_DIR)/<(node_lib_target_name)/src/node_dtrace_ustack.o',
] ]
} }
] ] ] ]

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_array", "target_name": "binding",
"sources": [ "test_array.c" ] "sources": [ "test_array.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for arrays // Testing api calls for arrays
const test_array = require(`./build/${common.buildType}/test_array`); const test_array = require(`./build/${common.buildType}/binding`);
const array = [ const array = [
1, 1,

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_async", "target_name": "binding",
"sources": [ "test_async.cc" ] "sources": [ "test_async.cc" ]
} }
] ]

View File

@ -2,7 +2,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const async_hooks = require('async_hooks'); const async_hooks = require('async_hooks');
const test_async = require(`./build/${common.buildType}/test_async`); const test_async = require(`./build/${common.buildType}/binding`);
const events = []; const events = [];
let testId; let testId;

View File

@ -2,7 +2,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const child_process = require('child_process'); const child_process = require('child_process');
const test_async = require(`./build/${common.buildType}/test_async`); const test_async = require(`./build/${common.buildType}/binding`);
const testException = 'test_async_cb_exception'; const testException = 'test_async_cb_exception';

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_buffer", "target_name": "binding",
"sources": [ "test_buffer.c" ] "sources": [ "test_buffer.c" ]
} }
] ]

View File

@ -2,7 +2,7 @@
// Flags: --expose-gc // Flags: --expose-gc
const common = require('../../common'); const common = require('../../common');
const binding = require(`./build/${common.buildType}/test_buffer`); const binding = require(`./build/${common.buildType}/binding`);
const assert = require('assert'); const assert = require('assert');
assert.strictEqual(binding.newBuffer().toString(), binding.theText); assert.strictEqual(binding.newBuffer().toString(), binding.theText);

View File

@ -1,12 +1,8 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_constructor", "target_name": "binding",
"sources": [ "test_constructor.c" ] "sources": [ "test_constructor.c" ]
},
{
"target_name": "test_constructor_name",
"sources": [ "test_constructor_name.c" ]
} }
] ]
} }

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for a constructor that defines properties // Testing api calls for a constructor that defines properties
const TestConstructor = require(`./build/${common.buildType}/test_constructor`); const TestConstructor = require(`./build/${common.buildType}/binding`);
const test_object = new TestConstructor(); const test_object = new TestConstructor();
assert.strictEqual(test_object.echo('hello'), 'hello'); assert.strictEqual(test_object.echo('hello'), 'hello');

View File

@ -0,0 +1,8 @@
{
"targets": [
{
"target_name": "binding",
"sources": [ "test_constructor_name.c" ]
}
]
}

View File

@ -3,6 +3,5 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for a constructor that defines properties // Testing api calls for a constructor that defines properties
const TestConstructor = const TestConstructor = require(`./build/${common.buildType}/binding`);
require(`./build/${common.buildType}/test_constructor_name`);
assert.strictEqual(TestConstructor.name, 'MyObject'); assert.strictEqual(TestConstructor.name, 'MyObject');

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_conversions", "target_name": "binding",
"sources": [ "test_conversions.c" ] "sources": [ "test_conversions.c" ]
} }
] ]

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const test = require(`./build/${common.buildType}/test_conversions`); const test = require(`./build/${common.buildType}/binding`);
const boolExpected = /boolean was expected/; const boolExpected = /boolean was expected/;
const numberExpected = /number was expected/; const numberExpected = /number was expected/;

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_dataview", "target_name": "binding",
"sources": [ "test_dataview.c" ] "sources": [ "test_dataview.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for arrays // Testing api calls for arrays
const test_dataview = require(`./build/${common.buildType}/test_dataview`); const test_dataview = require(`./build/${common.buildType}/binding`);
// Test for creating dataview // Test for creating dataview
{ {

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "store_env", "target_name": "binding",
"sources": [ "store_env.c" ] "sources": [ "store_env.c" ]
}, },
{ {

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const storeEnv = require(`./build/${common.buildType}/store_env`); const storeEnv = require(`./build/${common.buildType}/binding`);
const compareEnv = require(`./build/${common.buildType}/compare_env`); const compareEnv = require(`./build/${common.buildType}/compare_env`);
const assert = require('assert'); const assert = require('assert');

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_error", "target_name": "binding",
"sources": [ "test_error.cc" ] "sources": [ "test_error.cc" ]
} }
] ]

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const test_error = require(`./build/${common.buildType}/test_error`); const test_error = require(`./build/${common.buildType}/binding`);
const assert = require('assert'); const assert = require('assert');
const theError = new Error('Some error'); const theError = new Error('Some error');
const theTypeError = new TypeError('Some type error'); const theTypeError = new TypeError('Some type error');

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_exception", "target_name": "binding",
"sources": [ "test_exception.c" ] "sources": [ "test_exception.c" ]
} }
] ]

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const test_exception = require(`./build/${common.buildType}/test_exception`); const test_exception = require(`./build/${common.buildType}/binding`);
const assert = require('assert'); const assert = require('assert');
const theError = new Error('Some error'); const theError = new Error('Some error');
function throwTheError() { function throwTheError() {

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_fatal", "target_name": "binding",
"sources": [ "test_fatal.c" ] "sources": [ "test_fatal.c" ]
} }
] ]

View File

@ -2,7 +2,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const child_process = require('child_process'); const child_process = require('child_process');
const test_fatal = require(`./build/${common.buildType}/test_fatal`); const test_fatal = require(`./build/${common.buildType}/binding`);
// Test in a child process because the test code will trigger a fatal error // Test in a child process because the test code will trigger a fatal error
// that crashes the process. // that crashes the process.

View File

@ -2,7 +2,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const child_process = require('child_process'); const child_process = require('child_process');
const test_fatal = require(`./build/${common.buildType}/test_fatal`); const test_fatal = require(`./build/${common.buildType}/binding`);
// Test in a child process because the test code will trigger a fatal error // Test in a child process because the test code will trigger a fatal error
// that crashes the process. // that crashes the process.

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_function", "target_name": "binding",
"sources": [ "test_function.c" ] "sources": [ "test_function.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing api calls for function // testing api calls for function
const test_function = require(`./build/${common.buildType}/test_function`); const test_function = require(`./build/${common.buildType}/binding`);
function func1() { function func1() {

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_general", "target_name": "binding",
"sources": [ "test_general.c" ] "sources": [ "test_general.c" ]
} }
] ]

View File

@ -2,7 +2,7 @@
// Flags: --expose-gc // Flags: --expose-gc
const common = require('../../common'); const common = require('../../common');
const test_general = require(`./build/${common.buildType}/test_general`); const test_general = require(`./build/${common.buildType}/binding`);
const assert = require('assert'); const assert = require('assert');
const val1 = '1'; const val1 = '1';

View File

@ -2,7 +2,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const test_globals = require(`./build/${common.buildType}/test_general`); const test_globals = require(`./build/${common.buildType}/binding`);
assert.strictEqual(test_globals.getUndefined(), undefined); assert.strictEqual(test_globals.getUndefined(), undefined);
assert.strictEqual(test_globals.getNull(), null); assert.strictEqual(test_globals.getNull(), null);

View File

@ -6,7 +6,7 @@ const assert = require('assert');
// addon is referenced through the eval expression in testFile // addon is referenced through the eval expression in testFile
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const addon = require(`./build/${common.buildType}/test_general`); const addon = require(`./build/${common.buildType}/binding`);
const path = require('path'); const path = require('path');
// This test depends on a number of V8 tests. // This test depends on a number of V8 tests.

View File

@ -5,7 +5,7 @@ const assert = require('assert');
// addon is referenced through the eval expression in testFile // addon is referenced through the eval expression in testFile
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const addon = require(`./build/${common.buildType}/test_general`); const addon = require(`./build/${common.buildType}/binding`);
const testCase = '(41.92 + 0.08);'; const testCase = '(41.92 + 0.08);';
const expected = 42; const expected = 42;

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const addon = require(`./build/${common.buildType}/test_general`); const addon = require(`./build/${common.buildType}/binding`);
const assert = require('assert'); const assert = require('assert');
addon.createNapiError(); addon.createNapiError();

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_handle_scope", "target_name": "binding",
"sources": [ "test_handle_scope.c" ] "sources": [ "test_handle_scope.c" ]
} }
] ]

View File

@ -3,8 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing handle scope api calls // testing handle scope api calls
const testHandleScope = const testHandleScope = require(`./build/${common.buildType}/binding`);
require(`./build/${common.buildType}/test_handle_scope`);
testHandleScope.NewScope(); testHandleScope.NewScope();

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_number", "target_name": "binding",
"sources": [ "test_number.c" ] "sources": [ "test_number.c" ]
} }
] ]

View File

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const test_number = require(`./build/${common.buildType}/test_number`); const test_number = require(`./build/${common.buildType}/binding`);
// testing api calls for number // testing api calls for number

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_object", "target_name": "binding",
"sources": [ "test_object.c" ] "sources": [ "test_object.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for objects // Testing api calls for objects
const test_object = require(`./build/${common.buildType}/test_object`); const test_object = require(`./build/${common.buildType}/binding`);
const object = { const object = {

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_promise", "target_name": "binding",
"sources": [ "test_promise.c" ] "sources": [ "test_promise.c" ]
} }
] ]

View File

@ -5,7 +5,7 @@ const common = require('../../common');
// This tests the promise-related n-api calls // This tests the promise-related n-api calls
const assert = require('assert'); const assert = require('assert');
const test_promise = require(`./build/${common.buildType}/test_promise`); const test_promise = require(`./build/${common.buildType}/binding`);
common.crashOnUnhandledRejection(); common.crashOnUnhandledRejection();

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_properties", "target_name": "binding",
"sources": [ "test_properties.c" ] "sources": [ "test_properties.c" ]
} }
] ]

View File

@ -5,7 +5,7 @@ const readonlyErrorRE =
/^TypeError: Cannot assign to read only property '.*' of object '#<Object>'$/; /^TypeError: Cannot assign to read only property '.*' of object '#<Object>'$/;
// Testing api calls for defining properties // Testing api calls for defining properties
const test_object = require(`./build/${common.buildType}/test_properties`); const test_object = require(`./build/${common.buildType}/binding`);
assert.strictEqual(test_object.echo('hello'), 'hello'); assert.strictEqual(test_object.echo('hello'), 'hello');

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_reference", "target_name": "binding",
"sources": [ "test_reference.c" ] "sources": [ "test_reference.c" ]
} }
] ]

View File

@ -4,7 +4,7 @@
const common = require('../../common'); const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
const test_reference = require(`./build/${common.buildType}/test_reference`); const test_reference = require(`./build/${common.buildType}/binding`);
// This test script uses external values with finalizer callbacks // This test script uses external values with finalizer callbacks
// in order to track when values get garbage-collected. Each invocation // in order to track when values get garbage-collected. Each invocation

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_string", "target_name": "binding",
"sources": [ "test_string.c" ] "sources": [ "test_string.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing api calls for string // testing api calls for string
const test_string = require(`./build/${common.buildType}/test_string`); const test_string = require(`./build/${common.buildType}/binding`);
const empty = ''; const empty = '';
assert.strictEqual(test_string.TestLatin1(empty), empty); assert.strictEqual(test_string.TestLatin1(empty), empty);

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_symbol", "target_name": "binding",
"sources": [ "test_symbol.c" ] "sources": [ "test_symbol.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing api calls for symbol // testing api calls for symbol
const test_symbol = require(`./build/${common.buildType}/test_symbol`); const test_symbol = require(`./build/${common.buildType}/binding`);
const sym = test_symbol.New('test'); const sym = test_symbol.New('test');
assert.strictEqual(sym.toString(), 'Symbol(test)'); assert.strictEqual(sym.toString(), 'Symbol(test)');

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing api calls for symbol // testing api calls for symbol
const test_symbol = require(`./build/${common.buildType}/test_symbol`); const test_symbol = require(`./build/${common.buildType}/binding`);
const fooSym = test_symbol.New('foo'); const fooSym = test_symbol.New('foo');
const myObj = {}; const myObj = {};

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// testing api calls for symbol // testing api calls for symbol
const test_symbol = require(`./build/${common.buildType}/test_symbol`); const test_symbol = require(`./build/${common.buildType}/binding`);
assert.notStrictEqual(test_symbol.New(), test_symbol.New()); assert.notStrictEqual(test_symbol.New(), test_symbol.New());
assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('foo')); assert.notStrictEqual(test_symbol.New('foo'), test_symbol.New('foo'));

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_typedarray", "target_name": "binding",
"sources": [ "test_typedarray.c" ] "sources": [ "test_typedarray.c" ]
} }
] ]

View File

@ -3,7 +3,7 @@ const common = require('../../common');
const assert = require('assert'); const assert = require('assert');
// Testing api calls for arrays // Testing api calls for arrays
const test_typedarray = require(`./build/${common.buildType}/test_typedarray`); const test_typedarray = require(`./build/${common.buildType}/binding`);
const byteArray = new Uint8Array(3); const byteArray = new Uint8Array(3);
byteArray[0] = 0; byteArray[0] = 0;

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_uv_loop", "target_name": "binding",
"sources": [ "test_uv_loop.cc" ] "sources": [ "test_uv_loop.cc" ]
} }
] ]

View File

@ -1,5 +1,5 @@
'use strict'; 'use strict';
const common = require('../../common'); const common = require('../../common');
const { SetImmediate } = require(`./build/${common.buildType}/test_uv_loop`); const { SetImmediate } = require(`./build/${common.buildType}/binding`);
SetImmediate(common.mustCall()); SetImmediate(common.mustCall());

View File

@ -1,7 +1,7 @@
{ {
"targets": [ "targets": [
{ {
"target_name": "test_warning", "target_name": "binding",
"sources": [ "test_warning.c" ] "sources": [ "test_warning.c" ]
}, },
{ {

View File

@ -2,7 +2,7 @@
if (process.argv[2] === 'child') { if (process.argv[2] === 'child') {
const common = require('../../common'); const common = require('../../common');
console.log(require(`./build/${common.buildType}/test_warning`)); console.log(require(`./build/${common.buildType}/binding`));
console.log(require(`./build/${common.buildType}/test_warning2`)); console.log(require(`./build/${common.buildType}/test_warning2`));
} else { } else {
const run = require('child_process').spawnSync; const run = require('child_process').spawnSync;

View File

@ -1,5 +1,3 @@
.buildstamp
.docbuildstamp
Makefile Makefile
*.Makefile *.Makefile
*.mk *.mk

View File

@ -0,0 +1,52 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
namespace demo {
using v8::Exception;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
// This is the implementation of the "add" method
// Input arguments are passed using the
// const FunctionCallbackInfo<Value>& args struct
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
// Check the number of arguments passed.
if (args.Length() < 2) {
// Throw an Error that is passed back to JavaScript
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Wrong number of arguments")));
return;
}
// Check the argument types
if (!args[0]->IsNumber() || !args[1]->IsNumber()) {
isolate->ThrowException(Exception::TypeError(
String::NewFromUtf8(isolate, "Wrong arguments")));
return;
}
// Perform the operation
double value = args[0]->NumberValue() + args[1]->NumberValue();
Local<Number> num = Number::New(isolate, value);
// Set the return value (using the passed in
// FunctionCallbackInfo<Value>&)
args.GetReturnValue().Set(num);
}
void Init(Local<Object> exports) {
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","test.js"]}]}

View File

@ -0,0 +1,7 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
console.log('This should be eight:', binding.add(3, 5));

View File

@ -0,0 +1,30 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
namespace demo {
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Object;
using v8::String;
using v8::Value;
void RunCallback(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Function> cb = Local<Function>::Cast(args[0]);
const unsigned argc = 1;
Local<Value> argv[argc] = { String::NewFromUtf8(isolate, "hello world") };
cb->Call(Null(isolate), argc, argv);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", RunCallback);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","test.js"]}]}

View File

@ -0,0 +1,10 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
binding((msg) => {
console.log(msg);
// Prints: 'hello world'
});

View File

@ -0,0 +1,29 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Object> obj = Object::New(isolate);
obj->Set(String::NewFromUtf8(isolate, "msg"), args[0]->ToString());
args.GetReturnValue().Set(obj);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","test.js"]}]}

View File

@ -0,0 +1,10 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
const obj1 = binding('hello');
const obj2 = binding('world');
console.log(obj1.msg, obj2.msg);
// Prints: 'hello world'

View File

@ -0,0 +1,39 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
namespace demo {
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void MyFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(String::NewFromUtf8(isolate, "hello world"));
}
void CreateFunction(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, MyFunction);
Local<Function> fn = tpl->GetFunction();
// omit this to make it anonymous
fn->SetName(String::NewFromUtf8(isolate, "theFunction"));
args.GetReturnValue().Set(fn);
}
void Init(Local<Object> exports, Local<Object> module) {
NODE_SET_METHOD(module, "exports", CreateFunction);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, Init)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","test.js"]}]}

View File

@ -0,0 +1,9 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
const fn = binding();
console.log(fn());
// Prints: 'hello world'

View File

@ -0,0 +1,17 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Local;
using v8::Object;
void InitAll(Local<Object> exports) {
MyObject::Init(exports);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","myobject.h","myobject.cc","test.js"]}]}

View File

@ -0,0 +1,73 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.cc
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Local<Object> exports) {
Isolate* isolate = exports->GetIsolate();
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
constructor.Reset(isolate, tpl->GetFunction());
exports->Set(String::NewFromUtf8(isolate, "MyObject"),
tpl->GetFunction());
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Context> context = isolate->GetCurrentContext();
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> result =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(result);
}
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo

View File

@ -0,0 +1,27 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.h
#ifndef MYOBJECT_H // NOLINT(build/header_guard)
#define MYOBJECT_H // NOLINT(build/header_guard)
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Local<v8::Object> exports);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif // NOLINT(build/header_guard)

View File

@ -0,0 +1,13 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
const obj = new binding.MyObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13

View File

@ -0,0 +1,27 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void InitAll(Local<Object> exports, Local<Object> module) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(module, "exports", CreateObject);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","myobject.h","myobject.cc","test.js"]}]}

View File

@ -0,0 +1,83 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
// Prototype
NODE_SET_PROTOTYPE_METHOD(tpl, "plusOne", PlusOne);
constructor.Reset(isolate, tpl->GetFunction());
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
void MyObject::PlusOne(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj = ObjectWrap::Unwrap<MyObject>(args.Holder());
obj->value_ += 1;
args.GetReturnValue().Set(Number::New(isolate, obj->value_));
}
} // namespace demo

View File

@ -0,0 +1,28 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.h
#ifndef MYOBJECT_H // NOLINT(build/header_guard)
#define MYOBJECT_H // NOLINT(build/header_guard)
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void PlusOne(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif // NOLINT(build/header_guard)

View File

@ -0,0 +1,21 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const createObject = require(`./build/${common.buildType}/binding`);
const obj = createObject(10);
console.log(obj.plusOne());
// Prints: 11
console.log(obj.plusOne());
// Prints: 12
console.log(obj.plusOne());
// Prints: 13
const obj2 = createObject(20);
console.log(obj2.plusOne());
// Prints: 21
console.log(obj2.plusOne());
// Prints: 22
console.log(obj2.plusOne());
// Prints: 23

View File

@ -0,0 +1,42 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <node.h>
#include <node_object_wrap.h>
#include "myobject.h"
namespace demo {
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Number;
using v8::Object;
using v8::String;
using v8::Value;
void CreateObject(const FunctionCallbackInfo<Value>& args) {
MyObject::NewInstance(args);
}
void Add(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
MyObject* obj1 = node::ObjectWrap::Unwrap<MyObject>(
args[0]->ToObject());
MyObject* obj2 = node::ObjectWrap::Unwrap<MyObject>(
args[1]->ToObject());
double sum = obj1->value() + obj2->value();
args.GetReturnValue().Set(Number::New(isolate, sum));
}
void InitAll(Local<Object> exports) {
MyObject::Init(exports->GetIsolate());
NODE_SET_METHOD(exports, "createObject", CreateObject);
NODE_SET_METHOD(exports, "add", Add);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, InitAll)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","myobject.h","myobject.cc","test.js"]}]}

View File

@ -0,0 +1,70 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.cc
#include <node.h>
#include "myobject.h"
namespace demo {
using v8::Context;
using v8::Function;
using v8::FunctionCallbackInfo;
using v8::FunctionTemplate;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::Persistent;
using v8::String;
using v8::Value;
Persistent<Function> MyObject::constructor;
MyObject::MyObject(double value) : value_(value) {
}
MyObject::~MyObject() {
}
void MyObject::Init(Isolate* isolate) {
// Prepare constructor template
Local<FunctionTemplate> tpl = FunctionTemplate::New(isolate, New);
tpl->SetClassName(String::NewFromUtf8(isolate, "MyObject"));
tpl->InstanceTemplate()->SetInternalFieldCount(1);
constructor.Reset(isolate, tpl->GetFunction());
}
void MyObject::New(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.IsConstructCall()) {
// Invoked as constructor: `new MyObject(...)`
double value = args[0]->IsUndefined() ? 0 : args[0]->NumberValue();
MyObject* obj = new MyObject(value);
obj->Wrap(args.This());
args.GetReturnValue().Set(args.This());
} else {
// Invoked as plain function `MyObject(...)`, turn into construct call.
const int argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Context> context = isolate->GetCurrentContext();
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
}
void MyObject::NewInstance(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
const unsigned argc = 1;
Local<Value> argv[argc] = { args[0] };
Local<Function> cons = Local<Function>::New(isolate, constructor);
Local<Context> context = isolate->GetCurrentContext();
Local<Object> instance =
cons->NewInstance(context, argc, argv).ToLocalChecked();
args.GetReturnValue().Set(instance);
}
} // namespace demo

View File

@ -0,0 +1,28 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// myobject.h
#ifndef MYOBJECT_H // NOLINT(build/header_guard)
#define MYOBJECT_H // NOLINT(build/header_guard)
#include <node.h>
#include <node_object_wrap.h>
namespace demo {
class MyObject : public node::ObjectWrap {
public:
static void Init(v8::Isolate* isolate);
static void NewInstance(const v8::FunctionCallbackInfo<v8::Value>& args);
inline double value() const { return value_; }
private:
explicit MyObject(double value = 0);
~MyObject();
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static v8::Persistent<v8::Function> constructor;
double value_;
};
} // namespace demo
#endif // NOLINT(build/header_guard)

View File

@ -0,0 +1,12 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
const binding = require(`./build/${common.buildType}/binding`);
const obj1 = binding.createObject(10);
const obj2 = binding.createObject(20);
const result = binding.add(obj1, obj2);
console.log(result);
// Prints: 30

View File

@ -0,0 +1,47 @@
// Auto-generated by `node tools/doc/addon-verify.js`
// binding.cc
#include <assert.h>
#include <stdlib.h>
#include <node.h>
namespace demo {
using node::AtExit;
using v8::HandleScope;
using v8::Isolate;
using v8::Local;
using v8::Object;
static char cookie[] = "yum yum";
static int at_exit_cb1_called = 0;
static int at_exit_cb2_called = 0;
static void at_exit_cb1(void* arg) {
Isolate* isolate = static_cast<Isolate*>(arg);
HandleScope scope(isolate);
Local<Object> obj = Object::New(isolate);
assert(!obj.IsEmpty()); // assert VM is still alive
assert(obj->IsObject());
at_exit_cb1_called++;
}
static void at_exit_cb2(void* arg) {
assert(arg == static_cast<void*>(cookie));
at_exit_cb2_called++;
}
static void sanity_check(void*) {
assert(at_exit_cb1_called == 1);
assert(at_exit_cb2_called == 2);
}
void init(Local<Object> exports) {
AtExit(at_exit_cb2, cookie);
AtExit(at_exit_cb2, cookie);
AtExit(at_exit_cb1, exports->GetIsolate());
AtExit(sanity_check);
}
NODE_MODULE(NODE_GYP_MODULE_NAME, init)
} // namespace demo

View File

@ -0,0 +1,2 @@
# Auto-generated by `node tools/doc/addon-verify.js`
{"targets":[{"target_name":"binding","defines":["V8_DEPRECATION_WARNINGS=1"],"sources":["binding.cc","test.js"]}]}

View File

@ -0,0 +1,5 @@
// Auto-generated by `node tools/doc/addon-verify.js`
'use strict';
const common = require('../../common');
// test.js
require(`./build/${common.buildType}/binding`);

View File

@ -0,0 +1,6 @@
#include "node.h"
#include "v8.h"
inline void Initialize(v8::Local<v8::Object>) {}
NODE_MODULE(NODE_GYP_MODULE_NAME, Initialize)

View File

@ -1,5 +1,9 @@
{ {
'targets': [ 'targets': [
{
'target_name': 'binding',
'sources': [ 'binding.cc' ],
},
{ {
'target_name': 'testengine', 'target_name': 'testengine',
'type': 'none', 'type': 'none',

View File

@ -5,6 +5,7 @@ const fs = require('fs');
const path = require('path'); const path = require('path');
const marked = require('marked'); const marked = require('marked');
const auto = 'Auto-generated by `node tools/doc/addon-verify.js`';
const rootDir = path.resolve(__dirname, '..', '..'); const rootDir = path.resolve(__dirname, '..', '..');
const doc = path.resolve(rootDir, 'doc', 'api', 'addons.md'); const doc = path.resolve(rootDir, 'doc', 'api', 'addons.md');
const verifyDir = path.resolve(rootDir, 'test', 'addons'); const verifyDir = path.resolve(rootDir, 'test', 'addons');
@ -49,12 +50,20 @@ for (const header in addons) {
files = Object.entries(files).map(([name, content]) => { files = Object.entries(files).map(([name, content]) => {
if (name === 'test.js') content = boilerplate(name, content); if (name === 'test.js') content = boilerplate(name, content);
content = `// ${auto}\n${content}`;
if (name.endsWith('.h')) {
content = content.replace(/(#(ifndef|define) \w+_H)/g,
'$1 // NOLINT(build/header_guard)');
content = content.replace(/(#endif)$/,
'$1 // NOLINT(build/header_guard)');
}
if (!content.endsWith('\n')) content += '\n'; // Pacify linter.
return { name, content, path: path.resolve(dir, name) }; return { name, content, path: path.resolve(dir, name) };
}); });
files.push({ files.push({
path: path.resolve(dir, 'binding.gyp'), path: path.resolve(dir, 'binding.gyp'),
content: JSON.stringify({ content: `# ${auto}\n` + JSON.stringify({
targets: [ targets: [
{ {
target_name: 'binding', target_name: 'binding',