[Node.js binding] add build flag for node.js binding (#3948)

This commit is contained in:
Yulong Wang 2020-05-27 13:30:22 -07:00 committed by GitHub
parent ee6371d0a8
commit b3ec8035ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 184 additions and 50 deletions

View file

@ -124,7 +124,7 @@ GCC 4.x and below are not supported.
|**C# and C packages**|--build_csharp||
|**WindowsML**|--use_winml<br>--use_dml<br>--build_shared_lib|WindowsML depends on DirectML and the OnnxRuntime shared library|
|**Java**|--build_java|Creates an onnxruntime4j.jar in the build directory, implies `--build_shared_lib`<br>Compiling the Java API requires [gradle](https://gradle.org) v6.1+ to be installed in addition to the usual requirements.|
|**Node.js**|--build_nodejs|Implies `--build_shared_lib`<br>`npm install` to pull dev dependencies<br>`npm run build` to build binding<br>`npm test` to run tests|
|**Node.js**|--build_nodejs|Build Node.js binding. Implies `--build_shared_lib`|
---

View file

@ -1001,6 +1001,11 @@ if (onnxruntime_BUILD_JAVA)
include(onnxruntime_java.cmake)
endif()
if (onnxruntime_BUILD_NODEJS)
message(STATUS "Node.js Build is enabled")
include(onnxruntime_nodejs.cmake)
endif()
# some of the tests rely on the shared libs to be
# built; hence the ordering
if (onnxruntime_BUILD_UNIT_TESTS)

View file

@ -0,0 +1,36 @@
# Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
# Licensed under the MIT License.
set(NODEJS_BINDING_ROOT ${REPO_ROOT}/nodejs)
if (WIN32)
set(NPM_CLI cmd /c npm)
else()
set(NPM_CLI npm)
endif()
# verify Node.js and NPM
execute_process(COMMAND node --version
WORKING_DIRECTORY ${NODEJS_BINDING_ROOT}
OUTPUT_VARIABLE node_version
RESULT_VARIABLE had_error
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(had_error)
message(FATAL_ERROR "Failed to find Node.js: " ${had_error})
endif()
execute_process(COMMAND ${NPM_CLI} --version
WORKING_DIRECTORY ${NODEJS_BINDING_ROOT}
OUTPUT_VARIABLE npm_version
RESULT_VARIABLE had_error
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(had_error)
message(FATAL_ERROR "Failed to find NPM: " ${had_error})
endif()
# add custom target
add_custom_target(nodejs_binding_wrapper ALL
COMMAND ${NPM_CLI} ci --ort-skip-build
COMMAND ${NPM_CLI} run build -- --onnxruntime-build-dir=${CMAKE_CURRENT_BINARY_DIR} --config=${CMAKE_BUILD_TYPE}
COMMAND ${NPM_CLI} test -- --timeout=10000
WORKING_DIRECTORY ${NODEJS_BINDING_ROOT}
COMMENT "Using cmake-js to build OnnxRuntime Node.js binding")
add_dependencies(nodejs_binding_wrapper onnxruntime)

View file

@ -16,10 +16,21 @@ file(READ ${CMAKE_SOURCE_DIR}/../VERSION_NUMBER ort_version)
string(STRIP "${ort_version}" ort_version)
set(dist_folder "${CMAKE_SOURCE_DIR}/bin/napi-v3/${node_platform}/${node_arch}/")
# onnxruntime.dll dir
if(NOT ONNXRUNTIME_BUILD_DIR)
if (WIN32)
set(ONNXRUNTIME_BUILD_DIR ${CMAKE_SOURCE_DIR}/../build/Windows/${CMAKE_BUILD_TYPE})
else()
set(ONNXRUNTIME_BUILD_DIR ${CMAKE_SOURCE_DIR}/../build/Linux)
endif()
endif()
# include dirs
include_directories(${CMAKE_JS_INC})
include_directories(${CMAKE_SOURCE_DIR}/../include/onnxruntime)
include_directories(${CMAKE_SOURCE_DIR}/node_modules/node-addon-api)
# source files
file(GLOB SOURCE_FILES ${CMAKE_SOURCE_DIR}/src/*.cc)
add_library(onnxruntime_binding SHARED ${SOURCE_FILES} ${CMAKE_JS_SRC})
@ -29,16 +40,20 @@ set_target_properties(onnxruntime_binding PROPERTIES
INSTALL_RPATH_USE_LINK_PATH FALSE)
target_link_libraries(onnxruntime_binding PRIVATE ${CMAKE_JS_LIB})
# add libraries
if (WIN32)
target_link_libraries(onnxruntime_binding PRIVATE
${CMAKE_SOURCE_DIR}/../build/Windows/${CMAKE_BUILD_TYPE}/${CMAKE_BUILD_TYPE}/onnxruntime.lib)
target_link_directories(onnxruntime_binding PRIVATE ${ONNXRUNTIME_BUILD_DIR}/${CMAKE_BUILD_TYPE})
else()
target_link_directories(onnxruntime_binding PRIVATE ${ONNXRUNTIME_BUILD_DIR})
endif()
if (WIN32)
target_link_libraries(onnxruntime_binding PRIVATE onnxruntime.lib)
elseif (APPLE)
target_link_libraries(onnxruntime_binding PRIVATE
${CMAKE_SOURCE_DIR}/../build/Linux/${CMAKE_BUILD_TYPE}/libonnxruntime.${ort_version}.dylib)
target_link_libraries(onnxruntime_binding PRIVATE libonnxruntime.${ort_version}.dylib)
set_target_properties(onnxruntime_binding PROPERTIES INSTALL_RPATH "@loader_path")
else()
target_link_libraries(onnxruntime_binding PRIVATE
${CMAKE_SOURCE_DIR}/../build/Linux/${CMAKE_BUILD_TYPE}/libonnxruntime.so.${ort_version})
target_link_libraries(onnxruntime_binding PRIVATE libonnxruntime.so.${ort_version})
set_target_properties(onnxruntime_binding PROPERTIES INSTALL_RPATH "$ORIGIN/")
endif()
@ -54,14 +69,14 @@ if (WIN32)
add_custom_command(
TARGET onnxruntime_binding POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../build/Windows/${CMAKE_BUILD_TYPE}/${CMAKE_BUILD_TYPE}/onnxruntime.dll
${ONNXRUNTIME_BUILD_DIR}/${CMAKE_BUILD_TYPE}/onnxruntime.dll
${dist_folder}
)
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_custom_command(
TARGET onnxruntime_binding POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../build/Windows/${CMAKE_BUILD_TYPE}/${CMAKE_BUILD_TYPE}/onnxruntime.pdb
${ONNXRUNTIME_BUILD_DIR}/${CMAKE_BUILD_TYPE}/onnxruntime.pdb
${dist_folder}
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE_DIR:onnxruntime_binding>/onnxruntime_binding.pdb ${dist_folder}
)
@ -70,14 +85,14 @@ elseif (APPLE)
add_custom_command(
TARGET onnxruntime_binding POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../build/Linux/${CMAKE_BUILD_TYPE}/libonnxruntime.${ort_version}.dylib
${ONNXRUNTIME_BUILD_DIR}/libonnxruntime.${ort_version}.dylib
${dist_folder}
)
elseif (UNIX)
add_custom_command(
TARGET onnxruntime_binding POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_SOURCE_DIR}/../build/Linux/${CMAKE_BUILD_TYPE}/libonnxruntime.so.${ort_version}
${ONNXRUNTIME_BUILD_DIR}/libonnxruntime.so.${ort_version}
${dist_folder}
)
else()

View file

@ -1,24 +1,35 @@
# ONNX Runtime Node.js API
ONNX Runtime Node.js binding enables Node.js applications to run ONNX model inference.
## Usage
Install the latest stable version:
```
npm install onnxruntime
```
Install the latest dev version:
```
npm install onnxruntime@dev
```
Refer to [Node.js samples](../samples/README.md#Nodejs) for samples and tutorials.
## Requirements
Node.js version 12.x is required.
ONNXRuntime works on Node.js v12.x+ or Electron v5.x+.
### Supported Platforms
Following platforms are supported with pre-built binaries:
- Windows x64 CPU NAPI_v3
- Linux x64 CPU NAPI_v3
- MacOS x64 CPU NAPI_v3
## Usage
Samples can be found [here](../samples/nodejs).
Install the latest stable version: `npm install onnxruntime`
Install the latest dev version: `npm install onnxruntime@dev`
## Build
See [BUILD.MD](../BUILD.md#apis-and-language-bindings)
To use on platforms without pre-built binaries, you can build Node.js binding from source and consume it by `npm install <onnxruntime_repo_root>/nodejs/`. See also [BUILD.MD](../BUILD.md#apis-and-language-bindings) for building ONNX Runtime Node.js binding locally.
## License
License information can be found [here](../README.md#license).
License information can be found [here](../README.md#license).

View file

@ -190,6 +190,12 @@
"integrity": "sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w==",
"dev": true
},
"@types/minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=",
"dev": true
},
"@types/mocha": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",

View file

@ -7,9 +7,11 @@
"scripts": {
"install": "prebuild-install -r napi || (tsc && node ./script/build)",
"build": "tsc && node ./script/build",
"buildd": "tsc && node ./script/build --debug",
"buildd": "tsc && node ./script/build --config=Debug",
"buildr": "tsc && node ./script/build --config=RelWithDebInfo",
"rebuild": "tsc && node ./script/build --rebuild",
"rebuildd": "tsc && node ./script/build --debug --rebuild",
"rebuildd": "tsc && node ./script/build --rebuild --config=Debug",
"rebuildr": "tsc && node ./script/build --rebuild --config=RelWithDebInfo",
"test": "mocha ./test/test-main",
"lint": "eslint . --ext .ts",
"prepack": "node ./script/pack-prebuild",
@ -40,6 +42,7 @@
"devDependencies": {
"@types/fs-extra": "^8.1.0",
"@types/klaw-sync": "^6.0.0",
"@types/minimist": "1.2.0",
"@types/mocha": "^7.0.2",
"@types/tar-stream": "^2.1.0",
"@typescript-eslint/eslint-plugin": "^2.29.0",
@ -54,6 +57,7 @@
"globby": "^11.0.0",
"jsonc": "^2.0.0",
"klaw-sync": "^6.0.0",
"minimist": "^1.2.5",
"mocha": "^7.1.1",
"node-addon-api": "^2.0.0",
"node-pre-gyp-github": "^1.4.3",

View file

@ -1,14 +1,31 @@
import {execSync, spawnSync} from 'child_process';
import * as fs from 'fs-extra';
import minimist from 'minimist';
import * as path from 'path';
// NPM configs (parsed via 'npm install --xxx')
// skip build on install. usually used in CI where build will be another step.
const SKIP = !!process.env.npm_config_ort_skip_build;
if (SKIP) {
process.exit(0);
}
// command line flags
const DEBUG = process.argv.slice(2).indexOf('--debug') !== -1;
const REBUILD = process.argv.slice(2).indexOf('--rebuild') !== -1;
const buildArgs = minimist(process.argv.slice(2));
// currently only support Debug, Release and RelWithDebInfo
const CONFIG: 'Debug'|'Release'|'RelWithDebInfo' = buildArgs.config || 'RelWithDebInfo';
if (CONFIG !== 'Debug' && CONFIG !== 'Release' && CONFIG !== 'RelWithDebInfo') {
throw new Error(`unrecognized config: ${CONFIG}`);
}
const ONNXRUNTIME_BUILD_DIR = buildArgs['onnxruntime-build-dir'];
const REBUILD = !!buildArgs.rebuild;
// build path
const ROOT_FOLDER = path.join(__dirname, '..');
const BIN_FOLDER = path.join(ROOT_FOLDER, 'bin');
const BUILD_FOLDER = path.join(ROOT_FOLDER, 'build');
const NPM_BIN_FOLDER = execSync('npm bin', {encoding: 'utf8'}).trim();
const CMAKE_JS_FULL_PATH = path.join(NPM_BIN_FOLDER, 'cmake-js');
@ -16,19 +33,35 @@ const CMAKE_JS_FULL_PATH = path.join(NPM_BIN_FOLDER, 'cmake-js');
// if rebuild, clean up the dist folders
if (REBUILD) {
fs.removeSync(BIN_FOLDER);
fs.removeSync(BUILD_FOLDER);
}
const command = CMAKE_JS_FULL_PATH;
const args = [(REBUILD ? 'rebuild' : 'compile'), '--arch=x64', '--CDnapi_build_version=3'];
if (DEBUG) {
args.push('-D');
const args = [
(REBUILD ? 'reconfigure' : 'configure'),
'--arch=x64',
'--CDnapi_build_version=3',
`--CDCMAKE_BUILD_TYPE=${CONFIG}`,
];
if (ONNXRUNTIME_BUILD_DIR && typeof ONNXRUNTIME_BUILD_DIR === 'string') {
args.push(`--CDONNXRUNTIME_BUILD_DIR=${ONNXRUNTIME_BUILD_DIR}`);
}
// launch cmake-js
const proc = spawnSync(command, args, {shell: true, stdio: 'inherit', cwd: ROOT_FOLDER});
if (proc.status !== 0) {
if (proc.error) {
console.error(proc.error);
// launch cmake-js configure
const procCmakejs = spawnSync(command, args, {shell: true, stdio: 'inherit', cwd: ROOT_FOLDER});
if (procCmakejs.status !== 0) {
if (procCmakejs.error) {
console.error(procCmakejs.error);
}
process.exit(proc.status === null ? undefined : proc.status);
process.exit(procCmakejs.status === null ? undefined : procCmakejs.status);
}
// launch cmake to build
const procCmake =
spawnSync('cmake', ['--build', '.', '--config', CONFIG], {shell: true, stdio: 'inherit', cwd: BUILD_FOLDER});
if (procCmake.status !== 0) {
if (procCmake.error) {
console.error(procCmake.error);
}
process.exit(procCmake.status === null ? undefined : procCmake.status);
}

View file

@ -23,7 +23,7 @@ tarStream.pipe(zlib.createGzip({level: 9})).pipe(ws);
// enumerate all files under BIN folder
const entries = klawSync(BIN_FOLDER, {nodir: true}).map(i => ({
path: i.path,
name: path.relative(ROOT_FOLDER, i.path),
name: path.relative(ROOT_FOLDER, i.path).replace(/\\/g, '/'),
size: i.stats.size,
mode: i.stats.mode | parseInt('444', 8) | parseInt('222', 8),
gid: i.stats.gid,

View file

@ -22,5 +22,5 @@ describe('E2E Tests - InferenceSession.run()', async () => {
const result = await session!.run({'data_0': input0}, ['softmaxout_1']);
assertTensorEqual(result.softmaxout_1, expectedOutput0);
}
}).timeout('60s');
}).timeout('120s');
});

View file

@ -59,17 +59,25 @@ For a list of available dockerfiles and published images to help with getting st
* [MNIST inference](../java/src/test/java/sample/ScoreMNIST.java)
## Node.js
* [Basic Usage](./nodejs/01_basic-usage)
* [Create Tensor](./nodejs/01_basic-usage)
* [Create InferenceSession](./nodejs/01_basic-usage)
<!--
### [03 Create Tensor (Advanced)](./03_create-tensor-advanced/README.md)
This section contains several samples that demonstrate how to use onnxruntime Node.js binding.
This example is a demonstration of advanced usage of creating tensors.
### Samples
* [Basic Usage](./nodejs/01_basic-usage/) - a demonstration of basic usage of ONNX Runtime Node.js binding.
* [Create Tensor](./nodejs/02_create-tensor/) - a demonstration of basic usage of creating tensors.
<!--
* [Create Tensor (Advanced)](./nodejs/03_create-tensor-advanced/) - a demonstration of advanced usage of creating tensors.
-->
In each example's implementation subdirectory, run
* [Create InferenceSession](./nodejs/04_create-inference-session/) - shows how to create `InferenceSession` in different ways.
### Usage
In each sample's implementation subdirectory, run
```
npm install
node ./
```
```

View file

@ -166,6 +166,11 @@ def parse_arguments():
parser.add_argument(
"--build_java", action='store_true', help="Build Java bindings.")
# Node.js binding
parser.add_argument(
"--build_nodejs", action='store_true',
help="Build Node.js binding and NPM package.")
# Build a shared lib
parser.add_argument(
"--build_shared_lib", action='store_true',
@ -547,6 +552,7 @@ def generate_build_tree(cmake_path, source_dir, build_dir, cuda_home,
"ON" if args.enable_pybind else "OFF"),
"-Donnxruntime_BUILD_CSHARP=" + ("ON" if args.build_csharp else "OFF"),
"-Donnxruntime_BUILD_JAVA=" + ("ON" if args.build_java else "OFF"),
"-Donnxruntime_BUILD_NODEJS=" + ("ON" if args.build_nodejs else "OFF"),
"-Donnxruntime_BUILD_SHARED_LIB=" + (
"ON" if args.build_shared_lib else "OFF"),
"-Donnxruntime_USE_EIGEN_FOR_BLAS=" + (
@ -1561,7 +1567,7 @@ def main():
if args.build_wheel or args.gen_doc:
args.enable_pybind = True
if args.build_csharp or args.build_java:
if args.build_csharp or args.build_java or args.build_nodejs:
args.build_shared_lib = True
# Disabling unit tests for VAD-F as FPGA only supports

View file

@ -3,7 +3,7 @@ jobs:
parameters:
AgentPool : 'Linux-CPU'
JobName: 'Linux_CI_Dev'
BuildCommand: 'tools/ci_build/github/linux/run_dockerbuild.sh -o ubuntu16.04 -d cpu -r $(Build.BinariesDirectory) -x "--use_mklml --use_llvm --use_nuphar --use_dnnl --use_tvm --build_wheel --build_java --enable_language_interop_ops --use_featurizers --wheel_name_suffix featurizers"'
BuildCommand: 'tools/ci_build/github/linux/run_dockerbuild.sh -o ubuntu16.04 -d cpu -r $(Build.BinariesDirectory) -x "--use_mklml --use_llvm --use_nuphar --use_dnnl --use_tvm --build_wheel --build_java --build_nodejs --enable_language_interop_ops --use_featurizers --wheel_name_suffix featurizers"'
DoNugetPack: 'false'
ArtifactName: 'drop-linux'
TimeoutInMinutes: 120

View file

@ -2,4 +2,4 @@ jobs:
- template: templates/mac-ci.yml
parameters:
DoNugetPack: 'false'
BuildCommand: 'python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --use_openmp --build_dir $(Build.BinariesDirectory) --build_wheel --skip_submodule_sync --use_featurizers --parallel --build_shared_lib --build_java --enable_language_interop_ops --config Debug'
BuildCommand: 'python3 $(Build.SourcesDirectory)/tools/ci_build/build.py --use_openmp --build_dir $(Build.BinariesDirectory) --build_wheel --skip_submodule_sync --use_featurizers --parallel --build_shared_lib --build_java --build_nodejs --enable_language_interop_ops --config Debug'

View file

@ -18,6 +18,9 @@ jobs:
- checkout: self
${{ if ne(parameters.SubmoduleCheckoutMode, '') }}:
submodules: ${{ parameters.SubmoduleCheckoutMode }}
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- script: |
export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-11.jdk/Contents/Home
java --version

View file

@ -26,6 +26,10 @@ jobs:
addToPath: true
architecture: $(buildArch)
- task: NodeTool@0
inputs:
versionSpec: '12.x'
- task: BatchScript@1
displayName: 'setup env'
inputs:
@ -65,7 +69,7 @@ jobs:
displayName: 'Generate cmake config'
inputs:
scriptPath: '$(Build.SourcesDirectory)\tools\ci_build\build.py'
arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --build_wheel --use_featurizers --use_dnnl --use_winml --use_openmp --build_shared_lib --enable_onnx_tests --enable_wcos --build_java'
arguments: '--config $(BuildConfig) --build_dir $(Build.BinariesDirectory) --skip_submodule_sync --build_shared_lib --update --cmake_generator "Visual Studio 16 2019" --build_wheel --use_featurizers --use_dnnl --use_winml --use_openmp --build_shared_lib --enable_onnx_tests --enable_wcos --build_java --build_nodejs'
workingDirectory: '$(Build.BinariesDirectory)'
- task: VSBuild@1

View file

@ -82,6 +82,9 @@ if [[ $SYS_LONG_BIT = "64" && "$GLIBC_VERSION" -gt "9" ]]; then
echo "Installing cmake"
GetFile https://github.com/Kitware/CMake/releases/download/v3.13.5/cmake-3.13.5-Linux-x86_64.tar.gz /tmp/src/cmake-3.13.5-Linux-x86_64.tar.gz
tar -zxf /tmp/src/cmake-3.13.5-Linux-x86_64.tar.gz --strip=1 -C /usr
echo "Installing Node.js"
GetFile https://nodejs.org/dist/v12.16.3/node-v12.16.3-linux-x64.tar.xz /tmp/src/node-v12.16.3-linux-x64.tar.xz
tar -xf /tmp/src/node-v12.16.3-linux-x64.tar.xz --strip=1 -C /usr
else
echo "Installing cmake"
GetFile https://github.com/Kitware/CMake/releases/download/v3.13.5/cmake-3.13.5.tar.gz /tmp/src/cmake-3.13.5.tar.gz