onnxruntime-node
Version:
ONNXRuntime Node.js binding
135 lines (117 loc) • 5.43 kB
JavaScript
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
;
// This script is written in JavaScript. This is because it is used in "install" script in package.json, which is called
// when the package is installed either as a dependency or from "npm ci"/"npm install" without parameters. TypeScript is
// not always available.
// The purpose of this script is to download the required binaries for the platform and architecture.
// Currently, most of the binaries are already bundled in the package, except for the files that described in the file
// install-metadata.js.
//
// Some files (eg. the CUDA EP binaries) are not bundled because they are too large to be allowed in the npm registry.
// Instead, they are downloaded from the Nuget feed. The script will download the binaries if they are not already
// present in the NPM package.
// Step.1: Check if we should exit early
const os = require('os');
const path = require('path');
const { bootstrap: globalAgentBootstrap } = require('global-agent');
const { installPackages, parseInstallFlag } = require('./install-utils.js');
const INSTALL_METADATA = require('./install-metadata.js');
// Bootstrap global-agent to honor the proxy settings in
// environment variables, e.g. GLOBAL_AGENT_HTTPS_PROXY.
// See https://github.com/gajus/global-agent/blob/v3.0.0/README.md#environment-variables for details.
globalAgentBootstrap();
// commandline flag:
//
// --onnxruntime-node-install Force install the files that are not bundled in the package.
//
// --onnxruntime-node-install=skip Skip the installation of the files that are not bundled in the package.
//
// --onnxruntime-node-install=cuda12 Force install the CUDA EP binaries for CUDA 12.
//
// --onnxruntime-node-install-cuda Force install the CUDA EP binaries.
// (deprecated, use --onnxruntime-node-install=cuda12)
//
// --onnxruntime-node-install-cuda=skip Skip the installation of the CUDA EP binaries.
// (deprecated, use --onnxruntime-node-install=skip)
//
//
// Alternatively, use environment variable "ONNXRUNTIME_NODE_INSTALL" or "ONNXRUNTIME_NODE_INSTALL_CUDA" (deprecated).
//
// If the flag is not provided, the script will look up the metadata file to determine the manifest.
//
/**
* Possible values:
* - undefined: the default behavior. This is the value when no installation flag is specified.
*
* - false: skip installation. This is the value when the installation flag is set to "skip":
* --onnxruntime-node-install=skip
*
* - true: force installation. This is the value when the installation flag is set with no value:
* --onnxruntime-node-install
*
* - string: the installation flag is set to a specific value:
* --onnxruntime-node-install=cuda12
*/
const INSTALL_FLAG = parseInstallFlag();
// if installation is skipped, exit early
if (INSTALL_FLAG === false) {
process.exit(0);
}
// if installation is not specified, exit early when the installation is local (e.g. `npm ci` in <ORT_ROOT>/js/node/)
if (INSTALL_FLAG === undefined) {
const npm_config_local_prefix = process.env.npm_config_local_prefix;
const npm_package_json = process.env.npm_package_json;
const IS_LOCAL_INSTALL =
npm_config_local_prefix && npm_package_json && path.dirname(npm_package_json) === npm_config_local_prefix;
if (IS_LOCAL_INSTALL) {
process.exit(0);
}
}
const PLATFORM = `${os.platform()}/${os.arch()}`;
let INSTALL_MANIFEST_NAMES = INSTALL_METADATA.requirements[PLATFORM] ?? [];
// if installation is specified explicitly, validate the manifest
if (typeof INSTALL_FLAG === 'string') {
const installations = INSTALL_FLAG.split(',').map((x) => x.trim());
for (const installation of installations) {
if (INSTALL_MANIFEST_NAMES.indexOf(installation) === -1) {
throw new Error(`Invalid installation: ${installation} for platform: ${PLATFORM}`);
}
}
INSTALL_MANIFEST_NAMES = installations;
}
const BIN_FOLDER = path.join(__dirname, '..', 'bin/napi-v6', PLATFORM);
const INSTALL_MANIFESTS = [];
const PACKAGES = new Set();
for (const name of INSTALL_MANIFEST_NAMES) {
const manifest = INSTALL_METADATA.manifests[`${PLATFORM}:${name}`];
if (!manifest) {
throw new Error(`Manifest not found: ${name} for platform: ${PLATFORM}`);
}
for (const [filename, { package: pkg, path: pathInPackage }] of Object.entries(manifest)) {
const packageCandidates = INSTALL_METADATA.packages[pkg];
if (!packageCandidates) {
throw new Error(`Package information not found: ${pkg}`);
}
PACKAGES.add(packageCandidates);
INSTALL_MANIFESTS.push({
filepath: path.normalize(path.join(BIN_FOLDER, filename)),
packagesInfo: packageCandidates,
pathInPackage,
});
}
}
// If the installation flag is not specified, we do a check to see if the files are already installed.
if (INSTALL_FLAG === undefined) {
let hasMissingFiles = false;
for (const { filepath } of INSTALL_MANIFESTS) {
if (!require('fs').existsSync(filepath)) {
hasMissingFiles = true;
break;
}
}
if (!hasMissingFiles) {
process.exit(0);
}
}
void installPackages(PACKAGES, INSTALL_MANIFESTS, INSTALL_METADATA.feeds);