Skip to content
Skeleton for bindings to C++ libraries for Node.js using node-addon-api
C++ JavaScript Shell Python Makefile
Branch: master
Clone or download

Latest commit

artemp and springmeyer N-api (node-addon-api) (#161)
* N-API port initial implementation (WIP)

* clang-format

* default init `name_`

* default construct `name_` in initialiser list to address :

```
../src/object_async/hello_async.cpp:137:1: error: 'object_async::HelloObjectAsync::name_' should be initialized in the member initialization list [-Werror=effc++]
 HelloObjectAsync::HelloObjectAsync(Napi::CallbackInfo const& info)
```

changes. Lines starting

* clang-format

* mode clang-format

* remove extra init (tidy)

* make ctor explicit

* pass Function by const-ref

* annotate with NOLINT + fix passing Function by const-ref in standalone async.

* clang-format

* default 'in-class' init member variable `name_` to placate g++

* remove LTO flags on linux builds

* Revert "remove LTO flags on linux builds" - doh!

This reverts commit 4df69fc.

* fix .clang-format

* reimplement CPU intensive task and factor out into separate header
+ formatting + use `override final`

* more cleaning up

* remove redundant `override` c++11

* fix comment

* Make simpler

* Update npm packages

* add link to docs

* Remove Nan references + update link

* remove node-6 builds

* Allocate new Buffer and copy data into it.

* Add empty dtor to avoid memory leaks + make AsyncHelloWorker non-copyable

* clang-format

* clang-tidy

* require  mode-addon-api >= 2.0.0

* Take ownership of underlying data (NOTE: clang-tidy doesn't like this:)

* Add missing return statements

* Use latest (HEAD) hode-addon-api module (fixes SIGILL crash in "Control Flow Integriry" builds (-fsanitize=cfi) with v2.0.0)

* Fix test - use exact error message match

* sleep for 100ms to speed up tests running time

* Store name_ member variable by value + clang tidy

* clang-format

* Initialize result_

* c++ style

* Return std::unique_ptr<std::vector<char>> and stop abusing std::string::data with const_cast (clang-tidy)

* update to use std::vector<char>  + add gsl::owner<T> implementation + explicitely transfer ownership to keep clang-tidy happy (cppcoreguidelines-owning-memory)

* Only target node v10 and v12

* tidy .travis.yml

* Revert "tidy .travis.yml"

This reverts commit eaa4fbf.

* Revert "Only target node v10 and v12"

This reverts commit bd6bdb6.

* Fix (hopefully) .travis.yml syntax

* Update node versions

* Add AsyncHelloWorker_v2 implementation which uses `GetResult` method and default `OnOk()` and `OnError`.

* add node v13 targets

* clang-format

* Don't rely on order of args evaluation which is implemetation defined (e.g clang++ differs from GCC) + check `result_` before deref etc.

C++ standard 5.2.2.8 :
"The order of evaluation of arguments is unspecified. All side effects of argument expression evaluations take effect before the function is entered. The order of evaluation of the postfix expression and the argument expression list is unspecified."

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf

* Makefile - better target name

* Update link [skip ci]

* attempt to fix coverage problem

* suppress OS X specific leak

* remove references to nan in readme

* avoid re-running npm install when no needed

* use correct mason-js module

* update deps

Co-authored-by: Dane Springmeyer <dane@mapbox.com>
Latest commit d3250a9 Apr 3, 2020

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
bench Add memory stats option to bench tests (#102) Jan 9, 2018
cloudformation
docs N-api (node-addon-api) (#161) Apr 3, 2020
lib Add build docs (#51) Jul 12, 2017
scripts N-api (node-addon-api) (#161) Apr 3, 2020
src N-api (node-addon-api) (#161) Apr 3, 2020
test N-api (node-addon-api) (#161) Apr 3, 2020
.clang-format N-api (node-addon-api) (#161) Apr 3, 2020
.clang-tidy Upgrade mason deps (#152) Aug 21, 2018
.gitignore Debugging before publish (#116) Apr 13, 2018
.travis.yml N-api (node-addon-api) (#161) Apr 3, 2020
API.md Reorganize documentation (#53) Aug 3, 2017
CHANGELOG.md Add memory stats option to bench tests (#102) Jan 9, 2018
CODE_OF_CONDUCT.md code of conduct (#82) Oct 20, 2017
CONTRIBUTING.md Add clang tidy/format docs (#103) Jan 10, 2018
LICENSE.md Add license (#79) Oct 20, 2017
Makefile N-api (node-addon-api) (#161) Apr 3, 2020
README.md N-api (node-addon-api) (#161) Apr 3, 2020
binding.gyp N-api (node-addon-api) (#161) Apr 3, 2020
codecov.yml add codecode ignores Apr 12, 2017
common.gypi Remove -std=gnu++1y Jul 1, 2018
mason-versions.ini LLVM 7 (#154) Nov 9, 2018
package-lock.json N-api (node-addon-api) (#161) Apr 3, 2020
package.json N-api (node-addon-api) (#161) Apr 3, 2020

README.md

dancing skel Build Status codecov

A skeleton for building a C++ addon for Node.js. This is a small, helper repository that generates simple HelloWorld Javascript example constructors. The examples have a number of methods to demonstrate different ways to use the Node C+ API for building particular types of functionality (i.e. asynchronous functions). Use this repo as both a template for your own code as well as a learning tool if you're just starting to develop Node/C++ Addons.

Why port C++ to Node.js?. That's a great question! C++ is a high performance language that allows you to execute operations without clogging up the event loop. Node.js is single-threaded, which blocks execution. Even in highly optimized javascript code it may be impossible to improve performance. Passing heavy operations into C++ and subsequently into C++ workers can greatly improve the overall runtime of the code. Porting C++ code to Node.js is also referred to as creating an "Addon".

More examples of how to port C++ libraries to node can be found at nodejs.org/api/addons.html.

What's in the box? 📦

This repository itself can be cloned and edited to your needs. The skeleton prepares a C++ port to Node.js and provides the following for quick development:

  • Tests: created with Tape in the test/ directory. Travis CI file is prepared to build and test your project on every push.
  • Documentation: use this README as a template and customize for your own project. Also, this skeleton uses documentation.js to generate API documentation from JSDOC comments in the .cpp files. Docs are located in API.md.
  • Benchmarking: Easily test the performance of your code using the built-in benchmark tests provided in this skeleton.
  • Build system: node-pre-gyp generates binaries with the proper system architecture flags
  • Publishing: Structured as a node module with a package.json that can be deployed to NPM's registry.
  • Learning resources: Read the detailed inline comments within the example code to learn exactly what is happening behind the scenes. Also, check out the extended tour to learn more about Node/C++ Addon development, builds, Xcode, and more details about the configuration of this skeleton.

Installation

Each make command is specified in Makefile

git clone git@github.com:mapbox/node-cpp-skel.git
cd node-cpp-skel

# Build binaries. This looks to see if there were changes in the C++ code. This does not reinstall deps.
make

# Run tests
make test

# Cleans your current builds and removes potential cache
make clean

# Build binaries in Debug mode (https://github.com/mapbox/cpp/blob/master/glossary.md#debug-build)
make debug

# Cleans everything, including the things you download from the network in order to compile (ex: npm packages).
# This is useful if you want to nuke everything and start from scratch.
# For example, it's super useful for making sure everything works for Travis, production, someone else's machine, etc
make distclean

# This skel uses documentation.js to auto-generate API docs.
# If you'd like to generate docs for your code, you'll need to install documentation.js,
# and then add your subdirectory to the docs command in package.json
npm install -g documentation@4.0.0
npm run docs

NOTE: we are pinned to documentation@4.0.0 because 5.x removed C++ support: https://github.com/documentationjs/documentation/blob/master/CHANGELOG.md#500-2017-07-27

Customizing the compiler toolchain

By default we use clang++ via mason. The reason we do this is:

  • We want to run the latest and greatest compiler version, to catch the most bugs, provide the best developer experience, and trigger the most helpful warnings
  • We use clang-format to format the code and each version of clang-format formats code slightly differently. To avoid friction around this (and ensure all devs format the code the same) we default to using the same version of clang++ via mason.
  • We want to support LTO in the builds, which is difficult to do on linux unless you control the toolchain tightly.

The version of the clang++ binary (and related tools) is controlled by the mason-versions.ini, and uses mason-js uses to install the toolchain.

All that said, it is still absolutely possible and encouraged to compile your module with another compiler toolchain. In fact we hope that modules based on node-cpp-skel do this!

To customize the toolchain you can override the defaults by setting these environment variables: CXX, CC, LINK, AR, NM. For example to use g++-6 you could do:

export CXX="g++-6"
export CC="gcc-6"
export LINK="g++-6"
export AR="ar"
export NM="nm"
make

These environment variables will override the compiler toolchain defaults in make_global_settings in the binding.gyp.

Warnings as errors

By default the build errors on compiler warnings. To disable this do:

WERROR=false make

Sanitizers

You can run the sanitizers, to catch additional bugs, by doing:

make sanitize

The sanitizers are part of the compiler and are also run in a specific job on Travis.

Add Custom Code

Depending on your usecase, there are a variety of ways to start using this skeleton for your project.

Setup new project

Easily use this skeleton as a starting off point for a new custom project:

# Clone node-cpp-skel locally

git clone git@github.com:mapbox/node-cpp-skel.git
cd node-cpp-skel/

# Create your new repo on GitHub and have the remote repo url handy for liftoff
# Then run the liftoff script from within your local node-cpp-skel root directory.
#
# This will:
# - prompt you for the new name of your project and the new remote repo url
# - automatically create a new directory for your new project repo
# - create a new branch called "node-cpp-skel-port" within your new repo directory
# - add, commit, and push that branch to your new repo

./scripts/liftoff.sh

Add your code

Once your project has ported node-cpp-skel, follow these steps to integrate your own code:

  • Create a dir in ./src to hold your custom code. See the example code within /src for reference.
  • Add your new method or class to ./src/module.cpp, and #include it at the top
  • Add your new file-to-be-compiled to the list of target sources in ./binding.gyp
  • Run make and see what surprises await on your new journey ⛵️

Adding dependencies

With updated versions of npm, a package-lock.json file is created, which is now included in node-cpp-skel. See npm-and-package-lock.md for more info on how to interact with this file and how to add new dependencies.

Interactive Debugging

Code coverage

Code coverage is critical for knowing how well your tests actually test all your code. To see code coverage you can view current results online at codecov or you can build in a customized way and display coverage locally like:

make coverage

Note

Use // LCOV_EXCL_START and // LCOV_EXCL_STOP to ignore from codecov remotely. However, this won't ignore when running coverage locally.

For more details about what make coverage is doing under the hood see https://github.com/mapbox/cpp#code-coverage.

Contributing and License

Contributors are welcome! This repo exists as a place to gather C++/Node Addon knowledge that will benefit the larger community. Please contribute your knowledge if you'd like.

Node-cpp-skel is licensed under CC0. Attribution is not required, but definitely welcome! If your project uses this skeleton, please add the node-cpp-skel badge to your readme so that others can learn about the resource.

badge

To include the badge, paste this into your README.md file:

[![badge](https://mapbox.s3.amazonaws.com/cpp-assets/node-cpp-skel-badge_blue.svg)](https://github.com/mapbox/node-cpp-skel)

See CONTRIBUTING and LICENSE for more info.

You can’t perform that action at this time.