-
Notifications
You must be signed in to change notification settings - Fork 9
feat(pages): add N-API pages #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
avivkeller
wants to merge
5
commits into
main
Choose a base branch
from
napi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| --- | ||
| authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller | ||
| --- | ||
|
|
||
| # CMake.js | ||
|
|
||
| [CMake.js](https://github.com/cmake-js/cmake-js) is good build tool alternative to [node-gyp](/learn/napi/build-tools/node-gyp.md). CMake.js is based on the [CMake](https://cmake.org) tool which must be installed. | ||
avivkeller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### Pros | ||
|
|
||
| - Uses the CMake tool which is widely-adopted in the open source community. | ||
| - Ideal for existing C/C++ libraries already based on CMake. | ||
|
|
||
| ### Cons | ||
|
|
||
| - Not widely adopted in the Node community. | ||
|
|
||
| ## Installation | ||
|
|
||
| CMake.js requires that CMake is already installed. Installers are available on the [CMake website](https://cmake.org). | ||
|
|
||
| > macOS developers may find it more convenient to install CMake using [Homebrew](https://brew.sh). With Homebrew installed, CMake can be installed using a `brew install cmake` command. | ||
|
|
||
| You can verify your CMake installation with the command: | ||
|
|
||
| ```bash | ||
| cmake --version | ||
| ``` | ||
|
|
||
| As a Node native module developer, you may find it convenient to install CMake.js as a global command line tool: | ||
|
|
||
| ```bash | ||
| npm install cmake-js -g | ||
| ``` | ||
|
|
||
| You can verify your CMake.js installation with the command: | ||
|
|
||
| ```bash | ||
| cmake-js --version | ||
| ``` | ||
|
|
||
| ## package.json | ||
|
|
||
| Your `package.json` file needs to have a couple of entries for your native module to work with CMake.js. | ||
|
|
||
| Since your native module needs to be compiled using CMake.js on installation, the `scripts` property of your `package.json` file needs an `install` entry to make this happen: | ||
|
|
||
| ```json | ||
| "scripts": { | ||
| "install": "cmake-js compile" | ||
| } | ||
| ``` | ||
|
|
||
| It is unlikely that the users of your native module will have CMake.js installed as a global command line tool. Therefore, your project needs to declare a development dependency on CMake.js. This can be accomplished by entering this command: | ||
|
|
||
| ```bash | ||
| npm install cmake-js --save-dev | ||
| ``` | ||
|
|
||
| An alternative is to manually add the development dependency to your `package.json` file: | ||
|
|
||
| ```json | ||
| "devDependencies": { | ||
| "cmake-js": "^6.0.0" | ||
| } | ||
| ``` | ||
|
|
||
| An example of this approach is [available here](https://github.com/nodejs/node-addon-examples/blob/main/src/8-tooling/build_with_cmake/node-addon-api/package.json). | ||
|
|
||
| ## CMakeLists.txt | ||
|
|
||
| Native modules built on CMake.js have a `CMakeLists.txt` that describes how the module is to be built. The file serves the same purpose as the `binding.gyp` for projects that use `node-gyp`. | ||
|
|
||
| In addition to the entries required for any CMake build, additional entries are required when building native modules. | ||
|
|
||
| ### CMake.js | ||
|
|
||
| Here are the lines required for all native modules built using CMake.js: | ||
|
|
||
| ```cpp | ||
| project(napi-cmake-build-example) | ||
| include_directories(${CMAKE_JS_INC}) | ||
| file(GLOB SOURCE_FILES "hello.cc") | ||
| add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC}) | ||
| set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node") | ||
| target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB}) | ||
| ``` | ||
|
|
||
| ### NAPI_VERSION | ||
|
|
||
| When building a native module based on Node-API, it is important to declare the minimum Node-API version against which your module is designed to work. For CMake.js, this is accomplished by adding a line like this to the `CMakeLists.txt` file: | ||
|
|
||
| ```cpp | ||
| # define NAPI_VERSION | ||
| add_definitions(-DNAPI_VERSION=3) | ||
| ``` | ||
|
|
||
| > In the absence of other requirements, Node-API version 3 is a good choice as this is the Node-API version active when Node-API left experimental status. | ||
|
|
||
| ### node-addon-api | ||
|
|
||
| Additional configuration values are required for Node-API modules based on `node-addon-api`. | ||
|
|
||
| `node-addon-api` requires C++11. These configuration lines at the top of the `CMakeLists.txt` file specify this requirement: | ||
|
|
||
| ```cpp | ||
| cmake_minimum_required(VERSION 3.9) | ||
| cmake_policy(SET CMP0042 NEW) | ||
| set (CMAKE_CXX_STANDARD 11) | ||
| ``` | ||
|
|
||
| Modules based on `node-addon-api` include additional header files that are not part of Node itself. These lines instruct CMake.js where to find these files: | ||
|
|
||
| ```cpp | ||
| # Include Node-API wrappers | ||
| execute_process(COMMAND node -p "require('node-addon-api').include" | ||
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | ||
| OUTPUT_VARIABLE NODE_ADDON_API_DIR | ||
| ) | ||
| string(REPLACE "\n" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) | ||
| string(REPLACE "\"" "" NODE_ADDON_API_DIR ${NODE_ADDON_API_DIR}) | ||
| target_include_directories(${PROJECT_NAME} PRIVATE ${NODE_ADDON_API_DIR}) | ||
| ``` | ||
|
|
||
| An example of this approach is [available here](https://github.com/nodejs/node-addon-examples/blob/main/src/8-tooling/build_with_cmake/node-addon-api/CMakeLists.txt). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| authors: avivkeller | ||
| --- | ||
|
|
||
| # Build Tools | ||
|
|
||
| Building a native Node.js addon requires compiling C/C++ source code into a binary `.node` file that Node.js can load at runtime. This section covers the build tools available to you and the trade-offs between them. | ||
|
|
||
| ## Compiling on installation vs. distributing pre-built binaries | ||
|
|
||
| There are two broad strategies for shipping a native addon: | ||
|
|
||
| **Compile on the user's machine** - When a user runs `npm install`, the build tool compiles your C/C++ source on their system. This is simple to set up but requires every user to have a working C/C++ toolchain installed. | ||
|
|
||
| **Distribute pre-built binaries** - You compile binaries for each supported platform and architecture ahead of time and upload them somewhere users can download. Users who download a matching binary skip the compilation step entirely; others fall back to compiling locally. | ||
|
|
||
| ## Build tools covered in this section | ||
|
|
||
| - [node-gyp](/learn/napi/build-tools/node-gyp.md) - the default build tool bundled with npm; uses Google's GYP format and is nearly universally supported in the Node ecosystem | ||
| - [CMake.js](/learn/napi/build-tools/cmake-js.md) - a CMake-based alternative, well-suited for projects that already use CMake | ||
| - [node-pre-gyp](/learn/napi/build-tools/node-pre-gyp.md) - a layer on top of node-gyp for distributing pre-built binaries via Amazon S3 | ||
| - [prebuild](/learn/napi/build-tools/prebuild.md) - an alternative pre-build tool that publishes binaries as GitHub Releases | ||
avivkeller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller | ||
| --- | ||
|
|
||
| # node-gyp | ||
|
|
||
| [node-gyp](https://github.com/nodejs/node-gyp) is the standard build tool for native Node.js addons and is used by the vast majority of packages in the npm ecosystem. It is actively maintained by the Node.js team. Most of the examples on this site use node-gyp to build binaries. | ||
|
|
||
| node-gyp is based on Google's [GYP](https://gyp.gsrc.io/) build tool. GYP provides a single cross-platform configuration format for C/C++ builds. Although Google archived the upstream GYP repository, node-gyp continues to receive active development and maintenance independently. | ||
|
|
||
| > node-gyp requires **Python 3.6 or later**. Python 2 is not supported. The full list of requirements for each platform can be found in the [node-gyp installation docs](https://github.com/nodejs/node-gyp#installation). | ||
|
|
||
| node-gyp is included with npm; when npm sees `"gypfile": true` in `package.json`, it invokes node-gyp automatically during `npm install`. You can also install and use it directly: | ||
|
|
||
| ```bash | ||
| npm install -g node-gyp | ||
| ``` | ||
|
|
||
| For developers who find node-gyp too constraining, [CMake.js](/learn/napi/build-tools/cmake-js.md) is a good alternative. | ||
avivkeller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| ### Pros | ||
|
|
||
| - Included with npm - no separate global install required for consumers. | ||
| - Nearly universally used in the Node.js ecosystem, with broad documentation and community knowledge. | ||
| - Supports Windows, macOS, and Linux from a single `binding.gyp` configuration file. | ||
|
|
||
| ### Cons | ||
|
|
||
| - The underlying GYP format is no longer actively developed by Google. | ||
| - Some developers find GYP's configuration syntax verbose or difficult to debug. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| --- | ||
| authors: gabrielschulhof, NickNaso, jschlight, mhdawson, KevinEady, avivkeller | ||
| --- | ||
|
|
||
| # node-pre-gyp | ||
|
|
||
| One of the limitations of native addons is that they must be compiled for each target platform and architecture. Without pre-built binaries, every user who installs your package must have a working C/C++ toolchain on their machine. | ||
|
|
||
| [node-pre-gyp](https://github.com/mapbox/node-pre-gyp) solves this by letting you build binaries ahead of time, upload them to a remote location, and have users download the right binary at install time - falling back to compiling from source only if a matching binary is not available. | ||
|
|
||
| > Note that Node-API support was added to node-pre-gyp in version 0.8.0. | ||
|
|
||
| > [prebuild](/learn/napi/build-tools/prebuild.md) is an alternative tool that addresses the same problem. | ||
avivkeller marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| This page describes the changes required to a Node-API addon to support node-pre-gyp. | ||
|
|
||
| ## Amazon S3 | ||
|
|
||
| By default, node-pre-gyp uploads binaries to [Amazon S3](https://aws.amazon.com/s3/). | ||
|
|
||
| > The [node-pre-gyp-github](https://github.com/bchr02/node-pre-gyp-github) module adds support for publishing to GitHub Releases instead. | ||
|
|
||
| ### Amazon S3 Requirements | ||
|
|
||
| Before uploading you need: | ||
|
|
||
| 1. An Amazon Web Services account. | ||
| 2. An IAM user or role with permission to upload to S3. | ||
| 3. An [S3 bucket](https://docs.aws.amazon.com/AmazonS3/latest/userguide/UsingBucket.html) to host the binaries. | ||
|
|
||
| ### AWS Credentials | ||
|
|
||
| Never store credentials in your repository. node-pre-gyp supports two common approaches for providing credentials during development: | ||
|
|
||
| 1. A `~/.node_pre_gyprc` file: | ||
|
|
||
| ```json | ||
| { | ||
| "accessKeyId": "xxx", | ||
| "secretAccessKey": "xxx" | ||
| } | ||
| ``` | ||
|
|
||
| 2. Environment variables: | ||
|
|
||
| ```bash | ||
| export node_pre_gyp_accessKeyId=xxx | ||
| export node_pre_gyp_secretAccessKey=xxx | ||
| ``` | ||
|
|
||
| For CI environments, prefer IAM roles or short-lived credentials rather than long-lived access keys. See the [node-pre-gyp credentials documentation](https://github.com/mapbox/node-pre-gyp#3-configure-aws-credentials) for additional options. | ||
|
|
||
| ## package.json | ||
|
|
||
| ### The `dependencies` and `devDependencies` properties | ||
|
|
||
| The package is now published under the `@mapbox` scope. Use `aws-sdk` as a dev dependency for the upload step. | ||
|
|
||
| ```json | ||
| "dependencies": { | ||
| "@mapbox/node-pre-gyp": "^1.0.0" | ||
| }, | ||
| "devDependencies": { | ||
| "aws-sdk": "^2.0.0" | ||
| } | ||
| ``` | ||
|
|
||
| ### The `scripts` property | ||
|
|
||
| The `install` script should invoke node-pre-gyp with `--fallback-to-build` so that users who don't have a pre-built binary available can still compile locally: | ||
|
|
||
| ```json | ||
| "scripts": { | ||
| "install": "node-pre-gyp install --fallback-to-build" | ||
| } | ||
| ``` | ||
|
|
||
| ### The `binary` property | ||
|
|
||
| The `binary` property tells node-pre-gyp which Node-API versions your addon supports and where to find/upload binaries: | ||
|
|
||
| ```json | ||
| "binary": { | ||
| "module_name": "your_module", | ||
| "module_path": "./lib/binding/napi-v{napi_build_version}", | ||
| "remote_path": "./{module_name}/v{version}/{configuration}/", | ||
| "package_name": "{platform}-{arch}-napi-v{napi_build_version}.tar.gz", | ||
| "host": "https://your_bucket.s3.us-west-1.amazonaws.com", | ||
| "napi_versions": [3] | ||
| } | ||
| ``` | ||
|
|
||
| Set `module_name` to a valid C identifier. The `napi_versions` array lists which Node-API versions to build for; `3` is a reasonable minimum for most addons. | ||
|
|
||
| See the [node-pre-gyp docs](https://github.com/mapbox/node-pre-gyp#1-add-new-entries-to-your-packagejson) for a complete reference, including [Node-API considerations](https://github.com/mapbox/node-pre-gyp#n-api-considerations). | ||
|
|
||
| ## binding.gyp | ||
|
|
||
| ### New target | ||
|
|
||
| Add a post-build target to copy the compiled binary to the path specified by `module_path`: | ||
|
|
||
| ```json | ||
| { | ||
| "target_name": "action_after_build", | ||
| "type": "none", | ||
| "dependencies": ["<(module_name)"], | ||
| "copies": [ | ||
| { | ||
| "files": ["<(PRODUCT_DIR)/<(module_name).node"], | ||
| "destination": "<(module_path)" | ||
| } | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ### NAPI_VERSION | ||
|
|
||
| Include the Node-API version in the first target's `defines` so the header files configure themselves correctly: | ||
|
|
||
| ```json | ||
| "defines": [ | ||
| "NAPI_VERSION=<(napi_build_version)" | ||
| ] | ||
| ``` | ||
|
|
||
| ## JavaScript updates | ||
|
|
||
| JavaScript code that loads the native binary must dynamically resolve the path to the correct `.node` file: | ||
|
|
||
| ```cjs | ||
| const binary = require('@mapbox/node-pre-gyp'); | ||
| const path = require('path'); | ||
| const bindingPath = binary.find( | ||
| path.resolve(path.join(__dirname, './package.json')) | ||
| ); | ||
| const binding = require(bindingPath); | ||
| ``` | ||
|
|
||
| ## Build | ||
|
|
||
| Once everything is in place, build from source: | ||
|
|
||
| ```bash | ||
| npm install --build-from-source | ||
| ``` | ||
|
|
||
| ## Package and publish | ||
|
|
||
| ```bash | ||
| ./node_modules/.bin/node-pre-gyp package | ||
| ./node_modules/.bin/node-pre-gyp publish | ||
| ``` | ||
|
|
||
| ## CI and automated builds | ||
|
|
||
| Use [GitHub Actions](https://docs.github.com/en/actions) to build, test, and publish binaries for multiple platforms and architectures. A typical workflow matrix covers `ubuntu-latest`, `macos-latest`, and `windows-latest`, plus any architecture variants you need (e.g. `x64`, `arm64`). See the node-pre-gyp repository for [example workflow configurations](https://github.com/mapbox/node-pre-gyp). | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.