Socket
Book a DemoSign in
Socket

cmake-js

Package Overview
Dependencies
Maintainers
2
Versions
88
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cmake-js - npm Package Compare versions

Comparing version
7.3.0
to
7.3.1
+54
-96
changelog.md

@@ -1,7 +0,11 @@

v7.3.0 - 15/01/23
==========
# v7.3.1 - 17/04/25
- fix(windows): support windows arm64 (Thanks to @jaycex)
- fix(windows): support newer visual studio installations
# v7.3.0 - 15/01/24
- feat(windows): replace custom libnode.def generation with version from node-api-headers
- fix: support for vs2015 with nodejs 18 and older (#317)
- fix(windows): always remove Path if PATH is also defined (#319)
- fix(windows): always remove Path if PATH is also defined (#319)
- fix: Cmake arguments got converted to numbers (#314)

@@ -11,9 +15,7 @@ - fix: update node-api-headers

v7.2.1 - 14/02/23
==========
# v7.2.1 - 14/02/23
- fix: support Windows11SDK
v7.2.0 - 12/02/23
==========
# v7.2.0 - 12/02/23

@@ -24,9 +26,7 @@ - fix: `-DCMAKE_JS_VERSION=undefined` (#298)

v7.1.1 - 15/12/22
==========
# v7.1.1 - 15/12/22
- fix build errors on windows
v7.1.0 - 14/12/22
==========
# v7.1.0 - 14/12/22

@@ -37,4 +37,3 @@ - add commands for retrieving cmake-js include and lib directories

v7.0.0 - 08/10/22
==========
# v7.0.0 - 08/10/22

@@ -48,4 +47,3 @@ - update dependencies

v6.3.1 - 05/06/22
==========
# v6.3.1 - 05/06/22

@@ -56,4 +54,3 @@ - add missing bluebird dependency

v6.3.0 - 26/11/21
==========
# v6.3.0 - 26/11/21

@@ -65,19 +62,15 @@ - add offline mode: https://github.com/cmake-js/cmake-js/pull/260

v6.2.1 - 20/07/21
==========
# v6.2.1 - 20/07/21
- EOL hotfix (Thx Windows!)
v6.2.0 - 19/07/21
==========
# v6.2.0 - 19/07/21
- various fixes
v6.1.0 - 27/02/20
==========
# v6.1.0 - 27/02/20
- Add support for "-A/--platform" option to make target platform selectable for Visual Studio 2019 generator: https://github.com/cmake-js/cmake-js/pull/201
v6.0.0 - 30/09/19
=================
# v6.0.0 - 30/09/19

@@ -87,39 +80,31 @@ - Dropped compatibility of old Node.js runtimes (<10.0.0)

v5.3.2 - 21/08/19
=================
# v5.3.2 - 21/08/19
- Visual Studio detection fixes
v5.3.1 - 18/07/19
=================
# v5.3.1 - 18/07/19
- VS 2019 Support fix: https://github.com/cmake-js/cmake-js/pull/187
v5.3.0 - 09/07/19
=================
# v5.3.0 - 09/07/19
- VS 2019 Support: https://github.com/cmake-js/cmake-js/pull/178/, https://github.com/cmake-js/cmake-js/pull/184/
v5.2.1 - 10/04/19
=================
# v5.2.1 - 10/04/19
- Win delay load hook: https://github.com/cmake-js/cmake-js/pull/165/
v5.1.1 - 02/04/19
=================
# v5.1.1 - 02/04/19
- CMake 3.14 support fixed - https://github.com/cmake-js/cmake-js/pull/161
v5.1.0 - 14/02/19
=================
# v5.1.0 - 14/02/19
- CMake 3.14 support - https://github.com/cmake-js/cmake-js/pull/159
v5.0.1 - 24/01/19
=================
# v5.0.1 - 24/01/19
- Linux line ending hotfix (I hate Windows!)
v5.0.0 - 24/01/19
=================
# v5.0.0 - 24/01/19

@@ -130,9 +115,7 @@ - [semver major] Add case sensitive NPM config integration https://github.com/cmake-js/cmake-js/pull/151

v4.0.1 - 03/10/18
=================
# v4.0.1 - 03/10/18
- log argument hotfix https://github.com/cmake-js/cmake-js/pull/145
v4.0.0 - 14/09/18
=================
# v4.0.0 - 14/09/18

@@ -144,19 +127,15 @@ BREAKING CHANGES:

v3.7.3 - 16/05/18
=================
# v3.7.3 - 16/05/18
- npm config hotfix https://github.com/cmake-js/cmake-js/pull/123
v3.7.2 - 16/05/18
=================
# v3.7.2 - 16/05/18
- do not use, breaks ES5 compatibility
v3.7.1 - 07/05/18
=================
# v3.7.1 - 07/05/18
- Linux line ending hotfix (wat)
v3.7.0 - 07/05/18
=================
# v3.7.0 - 07/05/18

@@ -168,4 +147,3 @@ - PR: replace unzip with unzipper https://github.com/cmake-js/cmake-js/pull/120

v3.6.2 - 17/02/18
=================
# v3.6.2 - 17/02/18

@@ -175,34 +153,27 @@ - use https distribution download urls

v3.6.1 - 11/01/18
=================
# v3.6.1 - 11/01/18
- Detect 2017 Windows Build Tools
v3.6.0 - 11/27/17
=================
# v3.6.0 - 11/27/17
- "T" option for building specified target: https://github.com/cmake-js/cmake-js/pull/98
v3.5.0 - 06/21/17
=================
# v3.5.0 - 06/21/17
- Added Visual Studio 2017 compatibility: https://github.com/cmake-js/cmake-js/pull/78
v3.4.1 - 02/4/17
=================
# v3.4.1 - 02/4/17
- FIX: test output instead of guessing by platform: https://github.com/cmake-js/cmake-js/pull/77
v3.4.0 - 01/12/17
=================
# v3.4.0 - 01/12/17
- "G" option to set custom generators: https://github.com/cmake-js/cmake-js/pull/64
v3.3.1 - 09/13/16
=================
# v3.3.1 - 09/13/16
- fix of default parameters: https://github.com/cmake-js/cmake-js/pull/57
v3.3.0 - 09/02/16
=================
# v3.3.0 - 09/02/16

@@ -212,19 +183,15 @@ - silent option (https://github.com/cmake-js/cmake-js/pull/54)

v3.2.3 - 08/17/16
=================
# v3.2.3 - 08/17/16
- Line endings
v3.2.2 - 12/08/16
=================
# v3.2.2 - 12/08/16
- Multi directory support for Windows/MSVC build
v3.2.1 - 25/04/16
=================
# v3.2.1 - 25/04/16
- Linux line ending hotfix
v3.2.0 - 25/04/16
=================
# v3.2.0 - 25/04/16

@@ -235,19 +202,15 @@ - Added NW.js 0.13+ compatibility

v3.1.2 - 03/02/16
=================
# v3.1.2 - 03/02/16
- Fixed cmake-js binary ES5 compatibility.
v3.1.1 - 03/02/16
=================
# v3.1.1 - 03/02/16
- Fixed line endings
v3.1.0 - 03/02/16
=================
# v3.1.0 - 03/02/16
- Custom CMake parameter support (https://github.com/gerhardberger)
v3.0.0 - 20/11/15
=================
# v3.0.0 - 20/11/15

@@ -258,14 +221,11 @@ - Visual C++ Build Tools support

v2.1.0 - 29/10/15
=================
# v2.1.0 - 29/10/15
- explicit options for use GNU or Clang compiler instead of CMake's default (see --help for details)
v2.0.2 - 22/10/15
=================
# v2.0.2 - 22/10/15
- Fix: print-* commands report "undefined"
- Fix: print-\* commands report "undefined"
v2.0.0 - 17/10/15
=================
# v2.0.0 - 17/10/15

@@ -277,11 +237,9 @@ - Fix: distribution files only gets downloaded if needed (4.0.0+)

v1.1.1 - 06/10/15
=================
# v1.1.1 - 06/10/15
- Hotfix for build NW.js correctly.
v1.1.0 - 05/10/15
=================
# v1.1.0 - 05/10/15
- Node.js 4.0.0+ support
- Downloads the small, header only tarball for Node.js 4+

@@ -1,63 +0,58 @@

"use strict";
const path = require("path");
const isPlainObject = require("lodash.isplainobject");
'use strict'
const path = require('path')
function getConfig(lookPath, log) {
const pjsonPath = path.join(lookPath, "package.json");
log.silly("CFG", "Looking for package.json in: '" + pjsonPath + "'.");
try {
const json = require(pjsonPath);
log.silly("CFG", "Loaded:\n" + JSON.stringify(json));
if (isPlainObject(json) && isPlainObject(json["cmake-js"])) {
log.silly("CFG", "Config found.");
return json["cmake-js"];
}
else {
log.silly("CFG", "Config not found.");
return null;
}
}
catch (e) {
log.silly("CFG", "'package.json' not found.");
return null;
}
const pjsonPath = path.join(lookPath, 'package.json')
log.silly('CFG', "Looking for package.json in: '" + pjsonPath + "'.")
try {
const json = require(pjsonPath)
log.silly('CFG', 'Loaded:\n' + JSON.stringify(json))
if (json && json['cmake-js'] && typeof json['cmake-js'] === 'object') {
log.silly('CFG', 'Config found.')
return json['cmake-js']
} else {
log.silly('CFG', 'Config not found.')
return null
}
} catch (e) {
log.silly('CFG', "'package.json' not found.")
return null
}
}
module.exports = function (projectPath, log) {
log.verbose("CFG", "Looking for application level CMake.js config in '" + projectPath + ".");
let currPath = projectPath;
let lastConfig = null;
let currConfig;
for (; ;) {
currConfig = getConfig(currPath, log);
if (currConfig) {
lastConfig = currConfig;
}
try {
log.silly("CFG", "Looking for parent path.");
const lastPath = currPath;
currPath = path.normalize(path.join(currPath, ".."));
if (lastPath === currPath) {
currPath = null; // root
}
if (currPath) {
log.silly("CFG", "Parent path: '" + currPath + "'.");
}
}
catch (e) {
log.silly("CFG", "Exception:\n" + e.stack);
break;
}
if (currPath === null) {
log.silly("CFG", "Parent path with package.json file doesn't exists. Done.");
break;
}
}
if (lastConfig) {
log.verbose("CFG", "Application level CMake.js config found:\n" + JSON.stringify(lastConfig));
}
else {
log.verbose("CFG", "Application level CMake.js config doesn't exists.");
}
return lastConfig;
};
log.verbose('CFG', "Looking for application level CMake.js config in '" + projectPath + '.')
let currPath = projectPath
let lastConfig = null
let currConfig
for (;;) {
currConfig = getConfig(currPath, log)
if (currConfig) {
lastConfig = currConfig
}
try {
log.silly('CFG', 'Looking for parent path.')
const lastPath = currPath
currPath = path.normalize(path.join(currPath, '..'))
if (lastPath === currPath) {
currPath = null // root
}
if (currPath) {
log.silly('CFG', "Parent path: '" + currPath + "'.")
}
} catch (e) {
log.silly('CFG', 'Exception:\n' + e.stack)
break
}
if (currPath === null) {
log.silly('CFG', "Parent path with package.json file doesn't exists. Done.")
break
}
}
if (lastConfig) {
log.verbose('CFG', 'Application level CMake.js config found:\n' + JSON.stringify(lastConfig))
} else {
log.verbose('CFG', "Application level CMake.js config doesn't exists.")
}
return lastConfig
}

@@ -1,142 +0,123 @@

"use strict";
const CMake = require("./cMake");
const Dist = require("./dist");
const CMLog = require("./cmLog");
const appCMakeJSConfig = require("./appCMakeJSConfig");
const npmConfig = require("./npmConfig");
const path = require("path");
const isPlainObject = require("lodash.isplainobject");
const Toolset = require("./toolset");
'use strict'
const CMake = require('./cMake')
const Dist = require('./dist')
const CMLog = require('./cmLog')
const appCMakeJSConfig = require('./appCMakeJSConfig')
const npmConfig = require('./npmConfig')
const path = require('path')
const Toolset = require('./toolset')
function isNodeApi(log, projectRoot) {
try {
const projectPkgJson = require(path.join(projectRoot, 'package.json'))
// Make sure the property exists
return !!projectPkgJson?.binary?.napi_versions
} catch (e) {
log.silly("CFG", "'package.json' not found.");
return false
}
try {
const projectPkgJson = require(path.join(projectRoot, 'package.json'))
// Make sure the property exists
return !!projectPkgJson?.binary?.napi_versions
} catch (e) {
log.silly('CFG', "'package.json' not found.")
return false
}
}
function BuildSystem(options) {
this.options = options || {};
this.options.directory = path.resolve(this.options.directory || process.cwd());
this.options.out = path.resolve(this.options.out || path.join(this.options.directory, "build"));
this.log = new CMLog(this.options);
this.options.isNodeApi = isNodeApi(this.log, this.options.directory)
const appConfig = appCMakeJSConfig(this.options.directory, this.log);
const npmOptions = npmConfig(this.log);
class BuildSystem {
constructor(options) {
this.options = options || {}
this.options.directory = path.resolve(this.options.directory || process.cwd())
this.options.out = path.resolve(this.options.out || path.join(this.options.directory, 'build'))
this.log = new CMLog(this.options)
this.options.isNodeApi = isNodeApi(this.log, this.options.directory)
const appConfig = appCMakeJSConfig(this.options.directory, this.log)
const npmOptions = npmConfig(this.log)
if (isPlainObject(npmOptions) && Object.keys(npmOptions).length) {
this.options.runtimeDirectory = npmOptions["nodedir"];
this.options.msvsVersion = npmOptions['msvs_version']
}
if (isPlainObject(appConfig)) {
if (Object.keys(appConfig).length) {
this.log.verbose("CFG", "Applying CMake.js config from root package.json:");
this.log.verbose("CFG", JSON.stringify(appConfig));
// Applying applications's config, if there is no explicit runtime related options specified
this.options.runtime = this.options.runtime || appConfig.runtime;
this.options.runtimeVersion = this.options.runtimeVersion || appConfig.runtimeVersion;
this.options.arch = this.options.arch || appConfig.arch;
}
}
this.log.verbose("CFG", "Build system options:");
this.log.verbose("CFG", JSON.stringify(this.options));
this.cmake = new CMake(this.options);
this.dist = new Dist(this.options);
this.toolset = new Toolset(this.options);
if (npmOptions && typeof npmOptions === 'object' && Object.keys(npmOptions).length) {
this.options.runtimeDirectory = npmOptions['nodedir']
this.options.msvsVersion = npmOptions['msvs_version']
}
if (appConfig && typeof appConfig === 'object' && Object.keys(appConfig).length) {
this.log.verbose('CFG', 'Applying CMake.js config from root package.json:')
this.log.verbose('CFG', JSON.stringify(appConfig))
// Applying applications's config, if there is no explicit runtime related options specified
this.options.runtime = this.options.runtime || appConfig.runtime
this.options.runtimeVersion = this.options.runtimeVersion || appConfig.runtimeVersion
this.options.arch = this.options.arch || appConfig.arch
}
this.log.verbose('CFG', 'Build system options:')
this.log.verbose('CFG', JSON.stringify(this.options))
this.cmake = new CMake(this.options)
this.dist = new Dist(this.options)
this.toolset = new Toolset(this.options)
}
async _ensureInstalled() {
try {
await this.toolset.initialize(true)
if (!this.options.isNodeApi) {
await this.dist.ensureDownloaded()
}
} catch (e) {
this._showError(e)
throw e
}
}
_showError(e) {
if (this.log === undefined) {
// handle internal errors (init failed)
console.error('OMG', e.stack)
return
}
if (this.log.level === 'verbose' || this.log.level === 'silly') {
this.log.error('OMG', e.stack)
} else {
this.log.error('OMG', e.message)
}
}
install() {
return this._ensureInstalled()
}
async _invokeCMake(method) {
try {
await this._ensureInstalled()
return await this.cmake[method]()
} catch (e) {
this._showError(e)
throw e
}
}
getConfigureCommand() {
return this._invokeCMake('getConfigureCommand')
}
getCmakeJsLibString() {
return this._invokeCMake('getCmakeJsLibString')
}
getCmakeJsIncludeString() {
return this._invokeCMake('getCmakeJsIncludeString')
}
getCmakeJsSrcString() {
return this._invokeCMake('getCmakeJsSrcString')
}
configure() {
return this._invokeCMake('configure')
}
getBuildCommand() {
return this._invokeCMake('getBuildCommand')
}
build() {
return this._invokeCMake('build')
}
getCleanCommand() {
return this._invokeCMake('getCleanCommand')
}
clean() {
return this._invokeCMake('clean')
}
reconfigure() {
return this._invokeCMake('reconfigure')
}
rebuild() {
return this._invokeCMake('rebuild')
}
compile() {
return this._invokeCMake('compile')
}
}
BuildSystem.prototype._ensureInstalled = async function () {
try {
await this.toolset.initialize(true);
if (!this.options.isNodeApi) {
await this.dist.ensureDownloaded();
}
}
catch (e) {
this._showError(e);
throw e;
}
};
BuildSystem.prototype._showError = function (e) {
if (this.log === undefined) {
// handle internal errors (init failed)
console.error("OMG", e.stack);
return;
}
if (this.log.level === "verbose" || this.log.level === "silly") {
this.log.error("OMG", e.stack);
}
else {
this.log.error("OMG", e.message);
}
};
BuildSystem.prototype.install = function () {
return this._ensureInstalled();
};
BuildSystem.prototype._invokeCMake = async function (method) {
try {
await this._ensureInstalled();
return await this.cmake[method]();
}
catch (e) {
this._showError(e);
throw e;
}
};
BuildSystem.prototype.getConfigureCommand = function () {
return this._invokeCMake("getConfigureCommand");
};
BuildSystem.prototype.getCmakeJsLibString = function () {
return this._invokeCMake("getCmakeJsLibString");
};
BuildSystem.prototype.getCmakeJsIncludeString = function () {
return this._invokeCMake("getCmakeJsIncludeString");
};
BuildSystem.prototype.getCmakeJsSrcString = function () {
return this._invokeCMake("getCmakeJsSrcString");
};
BuildSystem.prototype.configure = function () {
return this._invokeCMake("configure");
};
BuildSystem.prototype.getBuildCommand = function () {
return this._invokeCMake("getBuildCommand");
};
BuildSystem.prototype.build = function () {
return this._invokeCMake("build");
};
BuildSystem.prototype.getCleanCommand = function () {
return this._invokeCMake("getCleanCommand");
};
BuildSystem.prototype.clean = function () {
return this._invokeCMake("clean");
};
BuildSystem.prototype.reconfigure = function () {
return this._invokeCMake("reconfigure");
};
BuildSystem.prototype.rebuild = function () {
return this._invokeCMake("rebuild");
};
BuildSystem.prototype.compile = function () {
return this._invokeCMake("compile");
};
module.exports = BuildSystem;
module.exports = BuildSystem
+329
-359

@@ -1,392 +0,362 @@

"use strict";
const which = require("which");
const fs = require("fs-extra");
const path = require("path");
const environment = require("./environment");
const Dist = require("./dist");
const CMLog = require("./cmLog");
const TargetOptions = require("./targetOptions");
const processHelpers = require("./processHelpers");
const locateNAN = require("./locateNAN");
const locateNodeApi = require("./locateNodeApi");
const npmConfigData = require("rc")("npm");
const Toolset = require("./toolset");
const headers = require('node-api-headers');
'use strict'
const which = require('which')
const fs = require('fs-extra')
const path = require('path')
const environment = require('./environment')
const Dist = require('./dist')
const CMLog = require('./cmLog')
const TargetOptions = require('./targetOptions')
const processHelpers = require('./processHelpers')
const locateNAN = require('./locateNAN')
const locateNodeApi = require('./locateNodeApi')
const npmConfigData = require('rc')('npm')
const Toolset = require('./toolset')
const headers = require('node-api-headers')
function CMake(options) {
this.options = options || {};
this.log = new CMLog(this.options);
this.dist = new Dist(this.options);
this.projectRoot = path.resolve(this.options.directory || process.cwd());
this.workDir = path.resolve(this.options.out || path.join(this.projectRoot, "build"));
this.config = this.options.config || (this.options.debug ? "Debug" : "Release");
this.buildDir = path.join(this.workDir, this.config);
this._isAvailable = null;
this.targetOptions = new TargetOptions(this.options);
this.toolset = new Toolset(this.options);
this.cMakeOptions = this.options.cMakeOptions || {};
this.extraCMakeArgs = this.options.extraCMakeArgs || [];
this.silent = !!options.silent;
}
class CMake {
get path() {
return this.options.cmakePath || 'cmake'
}
get isAvailable() {
if (this._isAvailable === null) {
this._isAvailable = CMake.isAvailable(this.options)
}
return this._isAvailable
}
Object.defineProperties(CMake.prototype, {
path: {
get: function () {
return this.options.cmakePath || "cmake";
}
},
isAvailable: {
get: function () {
if (this._isAvailable === null) {
this._isAvailable = CMake.isAvailable(this.options);
}
return this._isAvailable;
}
}
});
constructor(options) {
this.options = options || {}
this.log = new CMLog(this.options)
this.dist = new Dist(this.options)
this.projectRoot = path.resolve(this.options.directory || process.cwd())
this.workDir = path.resolve(this.options.out || path.join(this.projectRoot, 'build'))
this.config = this.options.config || (this.options.debug ? 'Debug' : 'Release')
this.buildDir = path.join(this.workDir, this.config)
this._isAvailable = null
this.targetOptions = new TargetOptions(this.options)
this.toolset = new Toolset(this.options)
this.cMakeOptions = this.options.cMakeOptions || {}
this.extraCMakeArgs = this.options.extraCMakeArgs || []
this.silent = !!options.silent
}
static isAvailable(options) {
options = options || {}
try {
if (options.cmakePath) {
const stat = fs.lstatSync(options.cmakePath)
return !stat.isDirectory()
} else {
which.sync('cmake')
return true
}
} catch (e) {
// Ignore
}
return false
}
static async getGenerators(options, log) {
const arch = ' [arch]'
options = options || {}
const gens = []
if (CMake.isAvailable(options)) {
// try parsing machine-readable capabilities (available since CMake 3.7)
try {
const stdout = await processHelpers.execFile([options.cmakePath || 'cmake', '-E', 'capabilities'])
const capabilities = JSON.parse(stdout)
return capabilities.generators.map((x) => x.name)
} catch (error) {
if (log) {
log.verbose('TOOL', 'Failed to query CMake capabilities (CMake is probably older than 3.7)')
}
}
CMake.isAvailable = function (options) {
options = options || {};
try {
if (options.cmakePath) {
const stat = fs.lstatSync(options.cmakePath);
return !stat.isDirectory();
}
else {
which.sync("cmake");
return true;
}
}
catch (e) {
// Ignore
}
return false;
};
// fall back to parsing help text
const stdout = await processHelpers.execFile([options.cmakePath || 'cmake', '--help'])
const hasCr = stdout.includes('\r\n')
const output = hasCr ? stdout.split('\r\n') : stdout.split('\n')
let on = false
output.forEach(function (line, i) {
if (on) {
const parts = line.split('=')
if (
(parts.length === 2 && parts[0].trim()) ||
(parts.length === 1 && i !== output.length - 1 && output[i + 1].trim()[0] === '=')
) {
let gen = parts[0].trim()
if (gen.endsWith(arch)) {
gen = gen.substr(0, gen.length - arch.length)
}
gens.push(gen)
}
}
if (line.trim() === 'Generators') {
on = true
}
})
} else {
throw new Error('CMake is not installed. Install CMake.')
}
return gens
}
verifyIfAvailable() {
if (!this.isAvailable) {
throw new Error(
"CMake executable is not found. Please use your system's package manager to install it, or you can get installers from there: http://cmake.org.",
)
}
}
async getConfigureCommand() {
// Create command:
let command = [this.path, this.projectRoot, '--no-warn-unused-cli']
CMake.getGenerators = async function (options, log) {
const arch = " [arch]";
options = options || {};
const gens = [];
if (CMake.isAvailable(options)) {
// try parsing machine-readable capabilities (available since CMake 3.7)
try {
const stdout = await processHelpers.execFile([options.cmakePath || "cmake", "-E", "capabilities"]);
const capabilities = JSON.parse(stdout);
return capabilities.generators.map(x => x.name);
}
catch (error) {
if (log) {
log.verbose("TOOL", "Failed to query CMake capabilities (CMake is probably older than 3.7)");
}
}
const D = []
// fall back to parsing help text
const stdout = await processHelpers.execFile([options.cmakePath || "cmake", "--help"]);
const hasCr = stdout.includes("\r\n");
const output = hasCr ? stdout.split("\r\n") : stdout.split("\n");
let on = false;
output.forEach(function (line, i) {
if (on) {
const parts = line.split("=");
if ((parts.length === 2 && parts[0].trim()) ||
(parts.length === 1 && i !== output.length - 1 && output[i + 1].trim()[0] === "=")) {
let gen = parts[0].trim();
if (gen.endsWith(arch)) {
gen = gen.substr(0, gen.length - arch.length);
}
gens.push(gen);
}
}
if (line.trim() === "Generators") {
on = true;
}
});
}
else {
throw new Error("CMake is not installed. Install CMake.");
}
return gens;
};
// CMake.js watermark
D.push({ CMAKE_JS_VERSION: environment.cmakeJsVersion })
CMake.prototype.getGenerators = function () {
return CMake.getGenerators(this.options, this.log);
};
// Build configuration:
D.push({ CMAKE_BUILD_TYPE: this.config })
if (environment.isWin) {
D.push({ CMAKE_RUNTIME_OUTPUT_DIRECTORY: this.workDir })
} else if (this.workDir.endsWith(this.config)) {
D.push({ CMAKE_LIBRARY_OUTPUT_DIRECTORY: this.workDir })
} else {
D.push({ CMAKE_LIBRARY_OUTPUT_DIRECTORY: this.buildDir })
}
CMake.prototype.verifyIfAvailable = function () {
if (!this.isAvailable) {
throw new Error("CMake executable is not found. Please use your system's package manager to install it, or you can get installers from there: http://cmake.org.");
}
};
// In some configurations MD builds will crash upon attempting to free memory.
// This tries to encourage MT builds which are larger but less likely to have this crash.
D.push({ CMAKE_MSVC_RUNTIME_LIBRARY: 'MultiThreaded$<$<CONFIG:Debug>:Debug>' })
CMake.prototype.getConfigureCommand = async function () {
// Includes:
const includesString = await this.getCmakeJsIncludeString()
D.push({ CMAKE_JS_INC: includesString })
// Create command:
let command = [this.path, this.projectRoot, "--no-warn-unused-cli"];
// Sources:
const srcsString = this.getCmakeJsSrcString()
D.push({ CMAKE_JS_SRC: srcsString })
const D = [];
// Runtime:
D.push({ NODE_RUNTIME: this.targetOptions.runtime })
D.push({ NODE_RUNTIMEVERSION: this.targetOptions.runtimeVersion })
D.push({ NODE_ARCH: this.targetOptions.arch })
// CMake.js watermark
D.push({"CMAKE_JS_VERSION": environment.cmakeJsVersion});
if (environment.isOSX) {
if (this.targetOptions.arch) {
let xcodeArch = this.targetOptions.arch
if (xcodeArch === 'x64') xcodeArch = 'x86_64'
D.push({ CMAKE_OSX_ARCHITECTURES: xcodeArch })
}
}
// Build configuration:
D.push({"CMAKE_BUILD_TYPE": this.config});
if (environment.isWin) {
D.push({"CMAKE_RUNTIME_OUTPUT_DIRECTORY": this.workDir});
}
else if (this.workDir.endsWith(this.config)) {
D.push({"CMAKE_LIBRARY_OUTPUT_DIRECTORY": this.workDir});
}
else {
D.push({"CMAKE_LIBRARY_OUTPUT_DIRECTORY": this.buildDir});
}
// Custom options
for (const [key, value] of Object.entries(this.cMakeOptions)) {
D.push({ [key]: value })
}
// In some configurations MD builds will crash upon attempting to free memory.
// This tries to encourage MT builds which are larger but less likely to have this crash.
D.push({"CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$<CONFIG:Debug>:Debug>"})
// Toolset:
await this.toolset.initialize(false)
// Includes:
const includesString = await this.getCmakeJsIncludeString();
D.push({ "CMAKE_JS_INC": includesString });
const libsString = this.getCmakeJsLibString()
D.push({ CMAKE_JS_LIB: libsString })
// Sources:
const srcsString = this.getCmakeJsSrcString();
D.push({ "CMAKE_JS_SRC": srcsString });
if (environment.isWin) {
const nodeLibDefPath = this.getNodeLibDefPath()
if (nodeLibDefPath) {
const nodeLibPath = path.join(this.workDir, 'node.lib')
D.push({ CMAKE_JS_NODELIB_DEF: nodeLibDefPath })
D.push({ CMAKE_JS_NODELIB_TARGET: nodeLibPath })
}
}
// Runtime:
D.push({"NODE_RUNTIME": this.targetOptions.runtime});
D.push({"NODE_RUNTIMEVERSION": this.targetOptions.runtimeVersion});
D.push({"NODE_ARCH": this.targetOptions.arch});
if (this.toolset.generator) {
command.push('-G', this.toolset.generator)
}
if (this.toolset.platform) {
command.push('-A', this.toolset.platform)
}
if (this.toolset.toolset) {
command.push('-T', this.toolset.toolset)
}
if (this.toolset.cppCompilerPath) {
D.push({ CMAKE_CXX_COMPILER: this.toolset.cppCompilerPath })
}
if (this.toolset.cCompilerPath) {
D.push({ CMAKE_C_COMPILER: this.toolset.cCompilerPath })
}
if (this.toolset.compilerFlags.length) {
D.push({ CMAKE_CXX_FLAGS: this.toolset.compilerFlags.join(' ') })
}
if (this.toolset.linkerFlags.length) {
D.push({ CMAKE_SHARED_LINKER_FLAGS: this.toolset.linkerFlags.join(' ') })
}
if (this.toolset.makePath) {
D.push({ CMAKE_MAKE_PROGRAM: this.toolset.makePath })
}
if (environment.isOSX) {
if (this.targetOptions.arch) {
let xcodeArch = this.targetOptions.arch
if (xcodeArch === 'x64') xcodeArch = 'x86_64'
D.push({CMAKE_OSX_ARCHITECTURES: xcodeArch})
}
}
// Load NPM config
for (const [key, value] of Object.entries(npmConfigData)) {
if (key.startsWith('cmake_')) {
const sk = key.substr(6)
if (sk && value) {
D.push({ [sk]: value })
}
}
}
// Custom options
for (const [key, value] of Object.entries(this.cMakeOptions)) {
D.push({ [key]: value });
}
command = command.concat(
D.map(function (p) {
return '-D' + Object.keys(p)[0] + '=' + Object.values(p)[0]
}),
)
// Toolset:
await this.toolset.initialize(false);
return command.concat(this.extraCMakeArgs)
}
getCmakeJsLibString() {
const libs = []
if (environment.isWin) {
const nodeLibDefPath = this.getNodeLibDefPath()
if (nodeLibDefPath) {
libs.push(path.join(this.workDir, 'node.lib'))
} else {
libs.push(...this.dist.winLibs)
}
}
return libs.join(';')
}
async getCmakeJsIncludeString() {
let incPaths = []
if (!this.options.isNodeApi) {
// Include and lib:
if (this.dist.headerOnly) {
incPaths = [path.join(this.dist.internalPath, '/include/node')]
} else {
const nodeH = path.join(this.dist.internalPath, '/src')
const v8H = path.join(this.dist.internalPath, '/deps/v8/include')
const uvH = path.join(this.dist.internalPath, '/deps/uv/include')
incPaths = [nodeH, v8H, uvH]
}
const libsString = this.getCmakeJsLibString()
D.push({ "CMAKE_JS_LIB": libsString });
// NAN
const nanH = await locateNAN(this.projectRoot)
if (nanH) {
incPaths.push(nanH)
}
} else {
// Base headers
const apiHeaders = require('node-api-headers')
incPaths.push(apiHeaders.include_dir)
if (environment.isWin) {
const nodeLibDefPath = this.getNodeLibDefPath()
if (nodeLibDefPath) {
const nodeLibPath = path.join(this.workDir, 'node.lib')
D.push({ CMAKE_JS_NODELIB_DEF: nodeLibDefPath })
D.push({ CMAKE_JS_NODELIB_TARGET: nodeLibPath })
}
}
// Node-api
const napiH = await locateNodeApi(this.projectRoot)
if (napiH) {
incPaths.push(napiH)
}
}
if (this.toolset.generator) {
command.push("-G", this.toolset.generator);
}
if (this.toolset.platform) {
command.push("-A", this.toolset.platform);
}
if (this.toolset.toolset) {
command.push("-T", this.toolset.toolset);
}
if (this.toolset.cppCompilerPath) {
D.push({"CMAKE_CXX_COMPILER": this.toolset.cppCompilerPath});
}
if (this.toolset.cCompilerPath) {
D.push({"CMAKE_C_COMPILER": this.toolset.cCompilerPath});
}
if (this.toolset.compilerFlags.length) {
D.push({"CMAKE_CXX_FLAGS": this.toolset.compilerFlags.join(" ")});
}
if (this.toolset.linkerFlags.length) {
D.push({"CMAKE_SHARED_LINKER_FLAGS": this.toolset.linkerFlags.join(" ")});
}
if (this.toolset.makePath) {
D.push({"CMAKE_MAKE_PROGRAM": this.toolset.makePath});
}
return incPaths.join(';')
}
getCmakeJsSrcString() {
const srcPaths = []
if (environment.isWin) {
const delayHook = path.normalize(path.join(__dirname, 'cpp', 'win_delay_load_hook.cc'))
// Load NPM config
for (const [key, value] of Object.entries(npmConfigData)) {
if (key.startsWith("cmake_")) {
const sk = key.substr(6);
if (sk && value) {
D.push({ [sk]: value });
}
}
}
srcPaths.push(delayHook.replace(/\\/gm, '/'))
}
command = command.concat(D.map(function (p) {
return "-D" + Object.keys(p)[0] + "=" + Object.values(p)[0];
}));
return srcPaths.join(';')
}
getNodeLibDefPath() {
return environment.isWin && this.options.isNodeApi ? headers.def_paths.node_api_def : undefined
}
async configure() {
this.verifyIfAvailable()
return command.concat(this.extraCMakeArgs);
};
this.log.info('CMD', 'CONFIGURE')
const listPath = path.join(this.projectRoot, 'CMakeLists.txt')
const command = await this.getConfigureCommand()
CMake.prototype.getCmakeJsLibString = function () {
try {
await fs.lstat(listPath)
} catch (e) {
throw new Error("'" + listPath + "' not found.")
}
const libs = []
if (environment.isWin) {
const nodeLibDefPath = this.getNodeLibDefPath()
if (nodeLibDefPath) {
libs.push(path.join(this.workDir, 'node.lib'))
} else {
libs.push(...this.dist.winLibs)
}
}
return libs.join(";");
};
try {
await fs.ensureDir(this.workDir)
} catch (e) {
// Ignore
}
CMake.prototype.getCmakeJsIncludeString = async function () {
let incPaths = [];
if (!this.options.isNodeApi) {
// Include and lib:
if (this.dist.headerOnly) {
incPaths = [path.join(this.dist.internalPath, "/include/node")];
}
else {
const nodeH = path.join(this.dist.internalPath, "/src");
const v8H = path.join(this.dist.internalPath, "/deps/v8/include");
const uvH = path.join(this.dist.internalPath, "/deps/uv/include");
incPaths = [nodeH, v8H, uvH];
}
const cwd = process.cwd()
process.chdir(this.workDir)
try {
await this._run(command)
} finally {
process.chdir(cwd)
}
}
async ensureConfigured() {
try {
await fs.lstat(path.join(this.workDir, 'CMakeCache.txt'))
} catch (e) {
await this.configure()
}
}
getBuildCommand() {
const command = [this.path, '--build', this.workDir, '--config', this.config]
if (this.options.target) {
command.push('--target', this.options.target)
}
if (this.options.parallel) {
command.push('--parallel', this.options.parallel)
}
return Promise.resolve(command.concat(this.extraCMakeArgs))
}
async build() {
this.verifyIfAvailable()
// NAN
const nanH = await locateNAN(this.projectRoot);
if (nanH) {
incPaths.push(nanH);
}
} else {
// Base headers
const apiHeaders = require('node-api-headers')
incPaths.push(apiHeaders.include_dir)
await this.ensureConfigured()
const buildCommand = await this.getBuildCommand()
this.log.info('CMD', 'BUILD')
await this._run(buildCommand)
}
getCleanCommand() {
return [this.path, '-E', 'remove_directory', this.workDir].concat(this.extraCMakeArgs)
}
clean() {
this.verifyIfAvailable()
// Node-api
const napiH = await locateNodeApi(this.projectRoot)
if (napiH) {
incPaths.push(napiH)
}
}
this.log.info('CMD', 'CLEAN')
return this._run(this.getCleanCommand())
}
async reconfigure() {
this.extraCMakeArgs = []
await this.clean()
await this.configure()
}
async rebuild() {
this.extraCMakeArgs = []
await this.clean()
await this.build()
}
async compile() {
this.extraCMakeArgs = []
try {
await this.build()
} catch (e) {
this.log.info('REP', 'Build has been failed, trying to do a full rebuild.')
await this.rebuild()
}
}
_run(command) {
this.log.info('RUN', command)
return processHelpers.run(command, { silent: this.silent })
}
return incPaths.join(";");
};
CMake.prototype.getCmakeJsSrcString = function () {
const srcPaths = [];
if (environment.isWin) {
const delayHook = path.normalize(path.join(__dirname, 'cpp', 'win_delay_load_hook.cc'));
srcPaths.push(delayHook.replace(/\\/gm, '/'));
}
return srcPaths.join(";");
};
CMake.prototype.getNodeLibDefPath = function () {
return environment.isWin && this.options.isNodeApi ? headers.def_paths.node_api_def : undefined
async getGenerators() {
return CMake.getGenerators(this.options, this.log)
}
}
CMake.prototype.configure = async function () {
this.verifyIfAvailable();
this.log.info("CMD", "CONFIGURE");
const listPath = path.join(this.projectRoot, "CMakeLists.txt");
const command = await this.getConfigureCommand();
try {
await fs.lstat(listPath);
}
catch (e) {
throw new Error("'" + listPath + "' not found.");
}
try {
await fs.ensureDir(this.workDir);
}
catch (e) {
// Ignore
}
const cwd = process.cwd();
process.chdir(this.workDir);
try {
await this._run(command);
}
finally {
process.chdir(cwd);
}
};
CMake.prototype.ensureConfigured = async function () {
try {
await fs.lstat(path.join(this.workDir, "CMakeCache.txt"));
}
catch (e) {
await this.configure();
}
};
CMake.prototype.getBuildCommand = function () {
const command = [this.path, "--build", this.workDir, "--config", this.config];
if (this.options.target) {
command.push("--target", this.options.target);
}
if (this.options.parallel) {
command.push("--parallel", this.options.parallel);
}
return Promise.resolve(command.concat(this.extraCMakeArgs));
};
CMake.prototype.build = async function () {
this.verifyIfAvailable();
await this.ensureConfigured();
const buildCommand = await this.getBuildCommand();
this.log.info("CMD", "BUILD");
await this._run(buildCommand);
};
CMake.prototype.getCleanCommand = function () {
return [this.path, "-E", "remove_directory", this.workDir].concat(this.extraCMakeArgs);
};
CMake.prototype.clean = function () {
this.verifyIfAvailable();
this.log.info("CMD", "CLEAN");
return this._run(this.getCleanCommand());
};
CMake.prototype.reconfigure = async function () {
this.extraCMakeArgs = [];
await this.clean();
await this.configure();
};
CMake.prototype.rebuild = async function () {
this.extraCMakeArgs = [];
await this.clean();
await this.build();
};
CMake.prototype.compile = async function () {
this.extraCMakeArgs = [];
try {
await this.build();
}
catch (e) {
this.log.info("REP", "Build has been failed, trying to do a full rebuild.");
await this.rebuild();
}
};
CMake.prototype._run = function (command) {
this.log.info("RUN", command);
return processHelpers.run(command, {silent: this.silent});
};
module.exports = CMake;
module.exports = CMake

@@ -1,76 +0,61 @@

"use strict";
const log = require("npmlog");
'use strict'
const log = require('npmlog')
function CMLog(options) {
this.options = options || {};
this.debug = require("debug")(this.options.logName || "cmake-js");
class CMLog {
get level() {
if (this.options.noLog) {
return 'silly'
} else {
return log.level
}
}
constructor(options) {
this.options = options || {}
this.debug = require('debug')(this.options.logName || 'cmake-js')
}
silly(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.silly(cat, msg)
}
}
verbose(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.verbose(cat, msg)
}
}
info(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.info(cat, msg)
}
}
warn(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.warn(cat, msg)
}
}
http(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.http(cat, msg)
}
}
error(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ': ' + msg)
} else {
log.error(cat, msg)
}
}
}
Object.defineProperties(CMLog.prototype, {
level: {
get: function() {
if (this.options.noLog) {
return "silly";
}
else {
return log.level;
}
}
}
});
CMLog.prototype.silly = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.silly(cat, msg);
}
};
CMLog.prototype.verbose = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.verbose(cat, msg);
}
};
CMLog.prototype.info = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.info(cat, msg);
}
};
CMLog.prototype.warn = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.warn(cat, msg);
}
};
CMLog.prototype.http = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.http(cat, msg);
}
};
CMLog.prototype.error = function(cat, msg) {
if (this.options.noLog) {
this.debug(cat + ": " + msg);
}
else {
log.error(cat, msg);
}
};
module.exports = CMLog;
module.exports = CMLog
+161
-180

@@ -1,195 +0,176 @@

"use strict";
const environment = require("./environment");
const path = require("path");
const urljoin = require("url-join");
const fs = require("fs-extra");
const CMLog = require("./cmLog");
const TargetOptions = require("./targetOptions");
const runtimePaths = require("./runtimePaths");
const Downloader = require("./downloader");
'use strict'
const environment = require('./environment')
const path = require('path')
const urljoin = require('url-join')
const fs = require('fs-extra')
const CMLog = require('./cmLog')
const TargetOptions = require('./targetOptions')
const runtimePaths = require('./runtimePaths')
const Downloader = require('./downloader')
const os = require('os')
function testSum(sums, sum, fPath) {
const serverSum = sums.find(function (s) {
return s.getPath === fPath;
});
if (serverSum && serverSum.sum === sum) {
return;
}
throw new Error("SHA sum of file '" + fPath + "' mismatch!");
const serverSum = sums.find(function (s) {
return s.getPath === fPath
})
if (serverSum && serverSum.sum === sum) {
return
}
throw new Error("SHA sum of file '" + fPath + "' mismatch!")
}
function Dist(options) {
this.options = options || {};
this.log = new CMLog(this.options);
this.targetOptions = new TargetOptions(this.options);
this.downloader = new Downloader(this.options);
}
class Dist {
get internalPath() {
const cacheDirectory = '.cmake-js'
const runtimeArchDirectory = this.targetOptions.runtime + '-' + this.targetOptions.arch
const runtimeVersionDirectory = 'v' + this.targetOptions.runtimeVersion
// Props
Object.defineProperties(Dist.prototype, {
internalPath: {
get: function () {
const cacheDirectory = ".cmake-js";
const runtimeArchDirectory = (this.targetOptions.runtime) + "-" + this.targetOptions.arch;
const runtimeVersionDirectory = "v" + this.targetOptions.runtimeVersion;
return (
this.options.runtimeDirectory ||
path.join(os.homedir(), cacheDirectory, runtimeArchDirectory, runtimeVersionDirectory)
)
}
get externalPath() {
return runtimePaths.get(this.targetOptions).externalPath
}
get downloaded() {
let headers = false
let libs = true
let stat = getStat(this.internalPath)
if (stat.isDirectory()) {
if (this.headerOnly) {
stat = getStat(path.join(this.internalPath, 'include/node/node.h'))
headers = stat.isFile()
} else {
stat = getStat(path.join(this.internalPath, 'src/node.h'))
if (stat.isFile()) {
stat = getStat(path.join(this.internalPath, 'deps/v8/include/v8.h'))
headers = stat.isFile()
}
}
if (environment.isWin) {
for (const libPath of this.winLibs) {
stat = getStat(libPath)
libs = libs && stat.isFile()
}
}
}
return headers && libs
return this.options.runtimeDirectory ||
path.join(environment.home,
cacheDirectory,
runtimeArchDirectory,
runtimeVersionDirectory);
}
},
externalPath: {
get: function () {
return runtimePaths.get(this.targetOptions).externalPath;
}
},
downloaded: {
get: function () {
let headers = false;
let libs = true;
let stat = getStat(this.internalPath);
if (stat.isDirectory()) {
if (this.headerOnly) {
stat = getStat(path.join(this.internalPath, "include/node/node.h"));
headers = stat.isFile();
}
else {
stat = getStat(path.join(this.internalPath, "src/node.h"));
if (stat.isFile()) {
stat = getStat(path.join(this.internalPath, "deps/v8/include/v8.h"));
headers = stat.isFile();
}
}
if (environment.isWin) {
for (const libPath of this.winLibs) {
stat = getStat(libPath);
libs = libs && stat.isFile();
}
}
}
return headers && libs;
function getStat(path) {
try {
return fs.statSync(path)
} catch (e) {
return {
isFile: () => false,
isDirectory: () => false,
}
}
}
}
get winLibs() {
const libs = runtimePaths.get(this.targetOptions).winLibs
const result = []
for (const lib of libs) {
result.push(path.join(this.internalPath, lib.dir, lib.name))
}
return result
}
get headerOnly() {
return runtimePaths.get(this.targetOptions).headerOnly
}
function getStat(path) {
try {
return fs.statSync(path);
}
catch (e) {
return {
isFile: () => false,
isDirectory: () => false
};
}
}
}
},
winLibs: {
get: function () {
const libs = runtimePaths.get(this.targetOptions).winLibs;
const result = [];
for (const lib of libs) {
result.push(path.join(this.internalPath, lib.dir, lib.name));
}
return result;
}
},
headerOnly: {
get: function () {
return runtimePaths.get(this.targetOptions).headerOnly;
}
}
});
constructor(options) {
this.options = options || {}
this.log = new CMLog(this.options)
this.targetOptions = new TargetOptions(this.options)
this.downloader = new Downloader(this.options)
}
// Methods
Dist.prototype.ensureDownloaded = async function () {
if (!this.downloaded) {
await this.download();
}
};
async ensureDownloaded() {
if (!this.downloaded) {
await this.download()
}
}
async download() {
const log = this.log
log.info('DIST', 'Downloading distribution files to: ' + this.internalPath)
await fs.ensureDir(this.internalPath)
const sums = await this._downloadShaSums()
await Promise.all([this._downloadLibs(sums), this._downloadTar(sums)])
}
async _downloadShaSums() {
if (this.targetOptions.runtime === 'node') {
const sumUrl = urljoin(this.externalPath, 'SHASUMS256.txt')
const log = this.log
log.http('DIST', '\t- ' + sumUrl)
return (await this.downloader.downloadString(sumUrl))
.split('\n')
.map(function (line) {
const parts = line.split(/\s+/)
return {
getPath: parts[1],
sum: parts[0],
}
})
.filter(function (i) {
return i.getPath && i.sum
})
} else {
return null
}
}
async _downloadTar(sums) {
const log = this.log
const self = this
const tarLocalPath = runtimePaths.get(self.targetOptions).tarPath
const tarUrl = urljoin(self.externalPath, tarLocalPath)
log.http('DIST', '\t- ' + tarUrl)
Dist.prototype.download = async function () {
const log = this.log;
log.info("DIST", "Downloading distribution files to: " + this.internalPath);
await fs.ensureDir(this.internalPath);
const sums = await this._downloadShaSums();
await Promise.all([this._downloadLibs(sums), this._downloadTar(sums)]);
};
const sum = await this.downloader.downloadTgz(tarUrl, {
hash: sums ? 'sha256' : null,
cwd: self.internalPath,
strip: 1,
filter: function (entryPath) {
if (entryPath === self.internalPath) {
return true
}
const ext = path.extname(entryPath)
return ext && ext.toLowerCase() === '.h'
},
})
Dist.prototype._downloadShaSums = async function () {
if (this.targetOptions.runtime === "node") {
const sumUrl = urljoin(this.externalPath, "SHASUMS256.txt");
const log = this.log;
log.http("DIST", "\t- " + sumUrl);
return (await this.downloader.downloadString(sumUrl))
.split("\n")
.map(function (line) {
const parts = line.split(/\s+/);
return {
getPath: parts[1],
sum: parts[0]
};
})
.filter(function (i) {
return i.getPath && i.sum;
});
}
else {
return null;
}
};
if (sums) {
testSum(sums, sum, tarLocalPath)
}
}
async _downloadLibs(sums) {
const log = this.log
const self = this
if (!environment.isWin) {
return
}
Dist.prototype._downloadTar = async function (sums) {
const log = this.log;
const self = this;
const tarLocalPath = runtimePaths.get(self.targetOptions).tarPath;
const tarUrl = urljoin(self.externalPath, tarLocalPath);
log.http("DIST", "\t- " + tarUrl);
const paths = runtimePaths.get(self.targetOptions)
for (const dirs of paths.winLibs) {
const subDir = dirs.dir
const fn = dirs.name
const fPath = subDir ? urljoin(subDir, fn) : fn
const libUrl = urljoin(self.externalPath, fPath)
log.http('DIST', '\t- ' + libUrl)
const sum = await this.downloader.downloadTgz(tarUrl, {
hash: sums ? "sha256" : null,
cwd: self.internalPath,
strip: 1,
filter: function (entryPath) {
if (entryPath === self.internalPath) {
return true;
}
const ext = path.extname(entryPath);
return ext && ext.toLowerCase() === ".h";
}
});
await fs.ensureDir(path.join(self.internalPath, subDir))
if (sums) {
testSum(sums, sum, tarLocalPath);
}
};
const sum = await this.downloader.downloadFile(libUrl, {
path: path.join(self.internalPath, fPath),
hash: sums ? 'sha256' : null,
})
Dist.prototype._downloadLibs = async function (sums) {
const log = this.log;
const self = this;
if (!environment.isWin) {
return;
}
if (sums) {
testSum(sums, sum, fPath)
}
}
}
}
const paths = runtimePaths.get(self.targetOptions);
for (const dirs of paths.winLibs) {
const subDir = dirs.dir;
const fn = dirs.name;
const fPath = subDir ? urljoin(subDir, fn) : fn;
const libUrl = urljoin(self.externalPath, fPath);
log.http("DIST", "\t- " + libUrl);
await fs.ensureDir(path.join(self.internalPath, subDir));
const sum = await this.downloader.downloadFile(libUrl, {
path: path.join(self.internalPath, fPath),
hash: sums ? "sha256" : null
});
if (sums) {
testSum(sums, sum, fPath);
}
}
};
module.exports = Dist;
module.exports = Dist

@@ -1,95 +0,92 @@

"use strict";
const crypto = require("crypto");
const axios = require("axios");
const MemoryStream = require("memory-stream");
const zlib = require("zlib");
const tar = require("tar");
const fs = require("fs");
const CMLog = require("./cmLog");
'use strict'
const crypto = require('crypto')
const axios = require('axios')
const MemoryStream = require('memory-stream')
const zlib = require('zlib')
const tar = require('tar')
const fs = require('fs')
const CMLog = require('./cmLog')
function Downloader(options) {
this.options = options || {};
this.log = new CMLog(this.options);
}
class Downloader {
constructor(options) {
this.options = options || {}
this.log = new CMLog(this.options)
}
downloadToStream(url, stream, hash) {
const self = this
const shasum = hash ? crypto.createHash(hash) : null
return new Promise(function (resolve, reject) {
let length = 0
let done = 0
let lastPercent = 0
axios
.get(url, { responseType: 'stream' })
.then(function (response) {
length = parseInt(response.headers['content-length'])
if (typeof length !== 'number') {
length = 0
}
Downloader.prototype.downloadToStream = function(url, stream, hash) {
const self = this;
const shasum = hash ? crypto.createHash(hash) : null;
return new Promise(function (resolve, reject) {
let length = 0;
let done = 0;
let lastPercent = 0;
axios
.get(url, { responseType: "stream" })
.then(function (response) {
length = parseInt(response.headers["content-length"]);
if (typeof length !== 'number') {
length = 0;
}
response.data.on('data', function (chunk) {
if (shasum) {
shasum.update(chunk)
}
if (length) {
done += chunk.length
let percent = (done / length) * 100
percent = Math.round(percent / 10) * 10 + 10
if (percent > lastPercent) {
self.log.verbose('DWNL', '\t' + lastPercent + '%')
lastPercent = percent
}
}
})
response.data.on('data', function (chunk) {
if (shasum) {
shasum.update(chunk);
}
if (length) {
done += chunk.length;
let percent = done / length * 100;
percent = Math.round(percent / 10) * 10 + 10;
if (percent > lastPercent) {
self.log.verbose("DWNL", "\t" + lastPercent + "%");
lastPercent = percent;
}
}
});
response.data.pipe(stream)
})
.catch(function (err) {
reject(err)
})
response.data.pipe(stream);
})
.catch(function (err) {
reject(err);
});
stream.once('error', function (err) {
reject(err)
})
stream.once("error", function (err) {
reject(err);
});
stream.once('finish', function () {
resolve(shasum ? shasum.digest('hex') : undefined)
})
})
}
async downloadString(url) {
const result = new MemoryStream()
await this.downloadToStream(url, result)
return result.toString()
}
async downloadFile(url, options) {
if (typeof options === 'string') {
options.path = options
}
const result = fs.createWriteStream(options.path)
const sum = await this.downloadToStream(url, result, options.hash)
this.testSum(url, sum, options)
return sum
}
async downloadTgz(url, options) {
if (typeof options === 'string') {
options.cwd = options
}
const gunzip = zlib.createGunzip()
const extractor = tar.extract(options)
gunzip.pipe(extractor)
const sum = await this.downloadToStream(url, gunzip, options.hash)
this.testSum(url, sum, options)
return sum
}
testSum(url, sum, options) {
if (options.hash && sum && options.sum && options.sum !== sum) {
throw new Error(options.hash.toUpperCase() + " sum of download '" + url + "' mismatch!")
}
}
}
stream.once("finish", function () {
resolve(shasum ? shasum.digest("hex") : undefined);
});
});
};
Downloader.prototype.downloadString = async function (url) {
const result = new MemoryStream();
await this.downloadToStream(url, result);
return result.toString();
};
Downloader.prototype.downloadFile = async function (url, options) {
if (typeof options === 'string') {
options.path = options;
}
const result = fs.createWriteStream(options.path);
const sum = await this.downloadToStream(url, result, options.hash);
this.testSum(url, sum, options);
return sum;
};
Downloader.prototype.downloadTgz = async function (url, options) {
if (typeof options === 'string') {
options.cwd = options;
}
const gunzip = zlib.createGunzip();
const extractor = tar.extract(options);
gunzip.pipe(extractor);
const sum = await this.downloadToStream(url, gunzip, options.hash);
this.testSum(url, sum, options);
return sum;
};
Downloader.prototype.testSum = function(url, sum, options) {
if (options.hash && sum && options.sum && options.sum !== sum) {
throw new Error(options.hash.toUpperCase() + " sum of download '" + url + "' mismatch!");
}
};
module.exports = Downloader;
module.exports = Downloader

@@ -1,107 +0,97 @@

"use strict";
const os = require("os");
const which = require("which");
'use strict'
const os = require('os')
const which = require('which')
const environment = module.exports = {
cmakeJsVersion: require("../package.json").version,
platform: os.platform(),
isWin: os.platform() === "win32",
isLinux: os.platform() === "linux",
isOSX: os.platform() === "darwin",
arch: os.arch(),
isX86: os.arch() === "ia32" || os.arch() === "x86",
isX64: os.arch() === "x64",
isArm: os.arch() === "arm",
runtime: "node",
runtimeVersion: process.versions.node,
home: process.env[(os.platform() === "win32") ? "USERPROFILE" : "HOME"],
EOL: os.EOL
};
const environment = (module.exports = {
cmakeJsVersion: require('../package.json').version,
platform: os.platform(),
isWin: os.platform() === 'win32',
isLinux: os.platform() === 'linux',
isOSX: os.platform() === 'darwin',
arch: os.arch(),
isX86: os.arch() === 'ia32' || os.arch() === 'x86',
isX64: os.arch() === 'x64',
isArm: os.arch() === 'arm',
isArm64: os.arch() === 'arm64',
runtime: 'node',
runtimeVersion: process.versions.node,
})
Object.defineProperties(environment, {
isPosix: {
get: function () {
return !this.isWin;
}
},
_isNinjaAvailable: {
value: null,
writable: true
},
isNinjaAvailable: {
get: function() {
if (this._isNinjaAvailable === null) {
this._isNinjaAvailable = false;
try {
if (which.sync("ninja")) {
this._isNinjaAvailable = true;
}
}
catch (e) {
// Ignore
}
}
return this._isNinjaAvailable;
}
},
_isMakeAvailable: {
value: null,
writable: true
},
isMakeAvailable: {
get: function() {
if (this._isMakeAvailable === null) {
this._isMakeAvailable = false;
try {
if (which.sync("make")) {
this._isMakeAvailable = true;
}
}
catch (e) {
// Ignore
}
}
return this._isMakeAvailable;
}
},
_isGPPAvailable: {
value: null,
writable: true
},
isGPPAvailable: {
get: function() {
if (this._isGPPAvailable === null) {
this._isGPPAvailable = false;
try {
if (which.sync("g++")) {
this._isGPPAvailable = true;
}
}
catch (e) {
// Ignore
}
}
return this._isGPPAvailable;
}
},
_isClangAvailable: {
value: null,
writable: true
},
isClangAvailable: {
get: function() {
if (this._isClangAvailable === null) {
this._isClangAvailable = false;
try {
if (which.sync("clang++")) {
this._isClangAvailable = true;
}
}
catch (e) {
// Ignore
}
}
return this._isClangAvailable;
}
}
});
_isNinjaAvailable: {
value: null,
writable: true,
},
isNinjaAvailable: {
get: function () {
if (this._isNinjaAvailable === null) {
this._isNinjaAvailable = false
try {
if (which.sync('ninja')) {
this._isNinjaAvailable = true
}
} catch (e) {
// Ignore
}
}
return this._isNinjaAvailable
},
},
_isMakeAvailable: {
value: null,
writable: true,
},
isMakeAvailable: {
get: function () {
if (this._isMakeAvailable === null) {
this._isMakeAvailable = false
try {
if (which.sync('make')) {
this._isMakeAvailable = true
}
} catch (e) {
// Ignore
}
}
return this._isMakeAvailable
},
},
_isGPPAvailable: {
value: null,
writable: true,
},
isGPPAvailable: {
get: function () {
if (this._isGPPAvailable === null) {
this._isGPPAvailable = false
try {
if (which.sync('g++')) {
this._isGPPAvailable = true
}
} catch (e) {
// Ignore
}
}
return this._isGPPAvailable
},
},
_isClangAvailable: {
value: null,
writable: true,
},
isClangAvailable: {
get: function () {
if (this._isClangAvailable === null) {
this._isClangAvailable = false
try {
if (which.sync('clang++')) {
this._isClangAvailable = true
}
} catch (e) {
// Ignore
}
}
return this._isClangAvailable
},
},
})

@@ -7,439 +7,587 @@ 'use strict'

const { regSearchKeys, execFile, logWithPrefix } = require('./util')
const semver = require("semver");
const semver = require('semver')
class VisualStudioFinder {
static findVisualStudio = (...args) => new VisualStudioFinder(...args).findVisualStudio()
static findVisualStudio = (...args) => new VisualStudioFinder(...args).findVisualStudio()
log = logWithPrefix(log, 'find VS')
log = logWithPrefix(log, 'find VS')
regSearchKeys = regSearchKeys
regSearchKeys = regSearchKeys
constructor (nodeSemver, configMsvsVersion) {
this.nodeSemver = nodeSemver
this.configMsvsVersion = configMsvsVersion
this.errorLog = []
this.validVersions = []
}
constructor(nodeSemver, configMsvsVersion) {
this.nodeSemver = nodeSemver
this.configMsvsVersion = configMsvsVersion
this.errorLog = []
this.validVersions = []
}
// Logs a message at verbose level, but also saves it to be displayed later
// at error level if an error occurs. This should help diagnose the problem.
addLog (message) {
this.log.verbose(message)
this.errorLog.push(message)
}
// Logs a message at verbose level, but also saves it to be displayed later
// at error level if an error occurs. This should help diagnose the problem.
addLog(message) {
this.log.verbose(message)
this.errorLog.push(message)
}
async findVisualStudio () {
this.configVersionYear = null
this.configPath = null
if (this.configMsvsVersion) {
this.addLog('msvs_version was set from command line or npm config')
if (this.configMsvsVersion.match(/^\d{4}$/)) {
this.configVersionYear = parseInt(this.configMsvsVersion, 10)
this.addLog(
`- looking for Visual Studio version ${this.configVersionYear}`)
} else {
this.configPath = path.resolve(this.configMsvsVersion)
this.addLog(
`- looking for Visual Studio installed in "${this.configPath}"`)
}
} else {
this.addLog('msvs_version not set from command line or npm config')
}
async findVisualStudio() {
this.configVersionYear = null
this.configPath = null
if (this.configMsvsVersion) {
this.addLog('msvs_version was set from command line or npm config')
if (this.configMsvsVersion.match(/^\d{4}$/)) {
this.configVersionYear = parseInt(this.configMsvsVersion, 10)
this.addLog(`- looking for Visual Studio version ${this.configVersionYear}`)
} else {
this.configPath = path.resolve(this.configMsvsVersion)
this.addLog(`- looking for Visual Studio installed in "${this.configPath}"`)
}
} else {
this.addLog('msvs_version not set from command line or npm config')
}
if (process.env.VCINSTALLDIR) {
this.envVcInstallDir =
path.resolve(process.env.VCINSTALLDIR, '..')
this.addLog('running in VS Command Prompt, installation path is:\n' +
`"${this.envVcInstallDir}"\n- will only use this version`)
} else {
this.addLog('VCINSTALLDIR not set, not running in VS Command Prompt')
}
if (process.env.VCINSTALLDIR) {
this.envVcInstallDir = path.resolve(process.env.VCINSTALLDIR, '..')
this.addLog(
'running in VS Command Prompt, installation path is:\n' +
`"${this.envVcInstallDir}"\n- will only use this version`,
)
} else {
this.addLog('VCINSTALLDIR not set, not running in VS Command Prompt')
}
const checks = [
() => this.findVisualStudio2017OrNewer(),
() => this.findVisualStudio2015(),
() => this.findVisualStudio2013()
]
const checks = [
() => this.findVisualStudio2019OrNewerFromSpecifiedLocation(),
() => this.findVisualStudio2019OrNewerUsingSetupModule(),
() => this.findVisualStudio2019OrNewer(),
() => this.findVisualStudio2017FromSpecifiedLocation(),
() => this.findVisualStudio2017UsingSetupModule(),
() => this.findVisualStudio2017(),
() => this.findVisualStudio2015(),
() => this.findVisualStudio2013(),
]
for (const check of checks) {
const info = await check()
if (info) {
return this.succeed(info)
}
}
for (const check of checks) {
const info = await check()
if (info) {
return this.succeed(info)
}
}
return this.fail()
}
return this.fail()
}
succeed (info) {
this.log.info(`using VS${info.versionYear} (${info.version}) found at:` +
`\n"${info.path}"` +
'\nrun with --verbose for detailed information')
return info
}
succeed(info) {
this.log.info(
`using VS${info.versionYear} (${info.version}) found at:` +
`\n"${info.path}"` +
'\nrun with --verbose for detailed information',
)
return info
}
fail () {
if (this.configMsvsVersion && this.envVcInstallDir) {
this.errorLog.push(
'msvs_version does not match this VS Command Prompt or the',
'installation cannot be used.')
} else if (this.configMsvsVersion) {
// If msvs_version was specified but finding VS failed, print what would
// have been accepted
this.errorLog.push('')
if (this.validVersions) {
this.errorLog.push('valid versions for msvs_version:')
this.validVersions.forEach((version) => {
this.errorLog.push(`- "${version}"`)
})
} else {
this.errorLog.push('no valid versions for msvs_version were found')
}
}
fail() {
if (this.configMsvsVersion && this.envVcInstallDir) {
this.errorLog.push('msvs_version does not match this VS Command Prompt or the', 'installation cannot be used.')
} else if (this.configMsvsVersion) {
// If msvs_version was specified but finding VS failed, print what would
// have been accepted
this.errorLog.push('')
if (this.validVersions) {
this.errorLog.push('valid versions for msvs_version:')
this.validVersions.forEach((version) => {
this.errorLog.push(`- "${version}"`)
})
} else {
this.errorLog.push('no valid versions for msvs_version were found')
}
}
const errorLog = this.errorLog.join('\n')
const errorLog = this.errorLog.join('\n')
// For Windows 80 col console, use up to the column before the one marked
// with X (total 79 chars including logger prefix, 62 chars usable here):
// X
const infoLog = [
'**************************************************************',
'You need to install the latest version of Visual Studio',
'including the "Desktop development with C++" workload.',
'For more information consult the documentation at:',
'https://github.com/nodejs/node-gyp#on-windows',
'**************************************************************'
].join('\n')
// For Windows 80 col console, use up to the column before the one marked
// with X (total 79 chars including logger prefix, 62 chars usable here):
// X
const infoLog = [
'**************************************************************',
'You need to install the latest version of Visual Studio',
'including the "Desktop development with C++" workload.',
'For more information consult the documentation at:',
'https://github.com/nodejs/node-gyp#on-windows',
'**************************************************************',
].join('\n')
this.log.error(`\n${errorLog}\n\n${infoLog}\n`)
throw new Error('Could not find any Visual Studio installation to use')
}
this.log.error(`\n${errorLog}\n\n${infoLog}\n`)
throw new Error('Could not find any Visual Studio installation to use')
}
// Invoke the PowerShell script to get information about Visual Studio 2017
// or newer installations
async findVisualStudio2017OrNewer () {
const ps = path.join(process.env.SystemRoot, 'System32',
'WindowsPowerShell', 'v1.0', 'powershell.exe')
const csFile = path.join(__dirname, 'Find-VisualStudio.cs')
const psArgs = [
'-ExecutionPolicy',
'Unrestricted',
'-NoProfile',
'-Command',
'&{Add-Type -Path \'' + csFile + '\';' + '[VisualStudioConfiguration.Main]::PrintJson()}'
]
async findVisualStudio2019OrNewerFromSpecifiedLocation() {
return this.findVSFromSpecifiedLocation([2019, 2022])
}
this.log.silly('Running', ps, psArgs)
const [err, stdout, stderr] = await execFile(ps, psArgs, { encoding: 'utf8' })
return this.parseData(err, stdout, stderr)
}
async findVisualStudio2017FromSpecifiedLocation() {
if (semver.gte(this.nodeSemver, '22.0.0')) {
this.addLog('not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findVSFromSpecifiedLocation([2017])
}
// Parse the output of the PowerShell script and look for an installation
// of Visual Studio 2017 or newer to use
parseData (err, stdout, stderr) {
this.log.silly('PS stderr = %j', stderr)
async findVSFromSpecifiedLocation(supportedYears) {
if (!this.envVcInstallDir) {
return null
}
const info = {
path: path.resolve(this.envVcInstallDir),
// Assume the version specified by the user is correct.
// Since Visual Studio 2015, the Developer Command Prompt sets the
// VSCMD_VER environment variable which contains the version information
// for Visual Studio.
// https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022
version: process.env.VSCMD_VER,
packages: [
'Microsoft.VisualStudio.Component.VC.Tools.x86.x64',
'Microsoft.VisualStudio.Component.VC.Tools.ARM64',
// Assume MSBuild exists. It will be checked in processing.
'Microsoft.VisualStudio.VC.MSBuild.Base',
],
}
const failPowershell = () => {
this.addLog(
'could not use PowerShell to find Visual Studio 2017 or newer, try re-running with \'--loglevel silly\' for more details')
return null
}
// Is there a better way to get SDK information?
const envWindowsSDKVersion = process.env.WindowsSDKVersion
const sdkVersionMatched = envWindowsSDKVersion?.match(/^(\d+)\.(\d+)\.(\d+)\..*/)
if (sdkVersionMatched) {
info.packages.push(`Microsoft.VisualStudio.Component.Windows10SDK.${sdkVersionMatched[3]}.Desktop`)
}
// pass for further processing
return this.processData([info], supportedYears)
}
if (err) {
this.log.silly('PS err = %j', err && (err.stack || err))
return failPowershell()
}
async findVisualStudio2019OrNewerUsingSetupModule() {
return this.findNewVSUsingSetupModule([2019, 2022])
}
let vsInfo
try {
vsInfo = JSON.parse(stdout)
} catch (e) {
this.log.silly('PS stdout = %j', stdout)
this.log.silly(e)
return failPowershell()
}
async findVisualStudio2017UsingSetupModule() {
if (semver.gte(this.nodeSemver, '22.0.0')) {
this.addLog('not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findNewVSUsingSetupModule([2017])
}
if (!Array.isArray(vsInfo)) {
this.log.silly('PS stdout = %j', stdout)
return failPowershell()
}
async findNewVSUsingSetupModule(supportedYears) {
const ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
const vcInstallDir = this.envVcInstallDir
vsInfo = vsInfo.map((info) => {
this.log.silly(`processing installation: "${info.path}"`)
info.path = path.resolve(info.path)
const ret = this.getVersionInfo(info)
ret.path = info.path
ret.msBuild = this.getMSBuild(info, ret.versionYear)
ret.toolset = this.getToolset(info, ret.versionYear)
ret.sdk = this.getSDK(info)
return ret
})
this.log.silly('vsInfo:', vsInfo)
const checkModuleArgs = [
'-NoProfile',
'-Command',
'&{@(Get-Module -ListAvailable -Name VSSetup).Version.ToString()}',
]
this.log.silly('Running', ps, checkModuleArgs)
const [cErr] = await this.execFile(ps, checkModuleArgs)
if (cErr) {
this.addLog(
'VSSetup module doesn\'t seem to exist. You can install it via: "Install-Module VSSetup -Scope CurrentUser"',
)
this.log.silly('VSSetup error = %j', cErr && (cErr.stack || cErr))
return null
}
const filterArg = vcInstallDir !== undefined ? `| where {$_.InstallationPath -eq '${vcInstallDir}' }` : ''
const psArgs = ['-NoProfile', '-Command', `&{Get-VSSetupInstance ${filterArg} | ConvertTo-Json -Depth 3}`]
// Remove future versions or errors parsing version number
vsInfo = vsInfo.filter((info) => {
if (info.versionYear) {
return true
}
this.addLog(`unknown version "${info.version}" found at "${info.path}"`)
return false
})
this.log.silly('Running', ps, psArgs)
const [err, stdout, stderr] = await this.execFile(ps, psArgs)
let parsedData = this.parseData(err, stdout, stderr)
if (parsedData === null) {
return null
}
this.log.silly('Parsed data', parsedData)
if (!Array.isArray(parsedData)) {
// if there are only 1 result, then Powershell will output non-array
parsedData = [parsedData]
}
// normalize output
parsedData = parsedData.map((info) => {
info.path = info.InstallationPath
info.version = `${info.InstallationVersion.Major}.${info.InstallationVersion.Minor}.${info.InstallationVersion.Build}.${info.InstallationVersion.Revision}`
info.packages = info.Packages.map((p) => p.Id)
return info
})
// pass for further processing
return this.processData(parsedData, supportedYears)
}
// Sort to place newer versions first
vsInfo.sort((a, b) => b.versionYear - a.versionYear)
// Invoke the PowerShell script to get information about Visual Studio 2019
// or newer installations
async findVisualStudio2019OrNewer() {
return this.findNewVS([2019, 2022])
}
for (let i = 0; i < vsInfo.length; ++i) {
const info = vsInfo[i]
this.addLog(`checking VS${info.versionYear} (${info.version}) found ` +
`at:\n"${info.path}"`)
// Invoke the PowerShell script to get information about Visual Studio 2017
async findVisualStudio2017() {
if (semver.gte(this.nodeSemver, '22.0.0')) {
this.addLog('not looking for VS2017 as it is only supported up to Node.js 21')
return null
}
return this.findNewVS([2017])
}
if (info.msBuild) {
this.addLog('- found "Visual Studio C++ core features"')
} else {
this.addLog('- "Visual Studio C++ core features" missing')
continue
}
// Invoke the PowerShell script to get information about Visual Studio 2017
// or newer installations
async findNewVS(supportedYears) {
const ps = path.join(process.env.SystemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe')
const csFile = path.join(__dirname, 'Find-VisualStudio.cs')
const psArgs = [
'-ExecutionPolicy',
'Unrestricted',
'-NoProfile',
'-Command',
"&{Add-Type -Path '" + csFile + "';" + '[VisualStudioConfiguration.Main]::PrintJson()}',
]
if (info.toolset) {
this.addLog(`- found VC++ toolset: ${info.toolset}`)
} else {
this.addLog('- missing any VC++ toolset')
continue
}
this.log.silly('Running', ps, psArgs)
const [err, stdout, stderr] = await this.execFile(ps, psArgs)
const parsedData = this.parseData(err, stdout, stderr, { checkIsArray: true })
if (parsedData === null) {
return null
}
return this.processData(parsedData, supportedYears)
}
if (info.sdk) {
this.addLog(`- found Windows SDK: ${info.sdk}`)
} else {
this.addLog('- missing any Windows SDK')
continue
}
// Parse the output of the PowerShell script, make sanity checks
parseData(err, stdout, stderr, sanityCheckOptions) {
const defaultOptions = {
checkIsArray: false,
}
if (!this.checkConfigVersion(info.versionYear, info.path)) {
continue
}
// Merging provided options with the default options
const sanityOptions = { ...defaultOptions, ...sanityCheckOptions }
return info
}
this.log.silly('PS stderr = %j', stderr)
this.addLog(
'could not find a version of Visual Studio 2017 or newer to use')
return null
}
const failPowershell = (failureDetails) => {
this.addLog(
`could not use PowerShell to find Visual Studio 2017 or newer, try re-running with '--loglevel silly' for more details. \n
Failure details: ${failureDetails}`,
)
return null
}
// Helper - process version information
getVersionInfo (info) {
const match = /^(\d+)\.(\d+)\..*/.exec(info.version)
if (!match) {
this.log.silly('- failed to parse version:', info.version)
return {}
}
this.log.silly('- version match = %j', match)
const ret = {
version: info.version,
versionMajor: parseInt(match[1], 10),
versionMinor: parseInt(match[2], 10)
}
if (ret.versionMajor === 15) {
ret.versionYear = 2017
return ret
}
if (ret.versionMajor === 16) {
ret.versionYear = 2019
return ret
}
if (ret.versionMajor === 17) {
ret.versionYear = 2022
return ret
}
this.log.silly('- unsupported version:', ret.versionMajor)
return {}
}
if (err) {
this.log.silly('PS err = %j', err && (err.stack || err))
return failPowershell(`${err}`.substring(0, 40))
}
msBuildPathExists (path) {
return existsSync(path)
}
let vsInfo
try {
vsInfo = JSON.parse(stdout)
} catch (e) {
this.log.silly('PS stdout = %j', stdout)
this.log.silly(e)
return failPowershell()
}
// Helper - process MSBuild information
getMSBuild (info, versionYear) {
const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base'
const msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe')
const msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe')
if (info.packages.indexOf(pkg) !== -1) {
this.log.silly('- found VC.MSBuild.Base')
if (versionYear === 2017) {
return path.join(info.path, 'MSBuild', '15.0', 'Bin', 'MSBuild.exe')
}
if (versionYear === 2019) {
return msbuildPath
}
}
/**
* Visual Studio 2022 doesn't have the MSBuild package.
* Support for compiling _on_ ARM64 was added in MSVC 14.32.31326,
* so let's leverage it if the user has an ARM64 device.
*/
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) {
return msbuildPathArm64
} else if (this.msBuildPathExists(msbuildPath)) {
return msbuildPath
}
return null
}
if (sanityOptions.checkIsArray && !Array.isArray(vsInfo)) {
this.log.silly('PS stdout = %j', stdout)
return failPowershell('Expected array as output of the PS script')
}
return vsInfo
}
// Helper - process toolset information
getToolset (info, versionYear) {
const pkg = 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64'
const express = 'Microsoft.VisualStudio.WDExpress'
// Process parsed data containing information about VS installations
// Look for the required parts, extract and output them back
processData(vsInfo, supportedYears) {
vsInfo = vsInfo.map((info) => {
this.log.silly(`processing installation: "${info.path}"`)
info.path = path.resolve(info.path)
const ret = this.getVersionInfo(info)
ret.path = info.path
ret.msBuild = this.getMSBuild(info, ret.versionYear)
ret.toolset = this.getToolset(info, ret.versionYear)
ret.sdk = this.getSDK(info)
return ret
})
this.log.silly('vsInfo:', vsInfo)
if (info.packages.indexOf(pkg) !== -1) {
this.log.silly('- found VC.Tools.x86.x64')
} else if (info.packages.indexOf(express) !== -1) {
this.log.silly('- found Visual Studio Express (looking for toolset)')
} else {
return null
}
// Remove future versions or errors parsing version number
// Also remove any unsupported versions
vsInfo = vsInfo.filter((info) => {
if (info.versionYear && supportedYears.indexOf(info.versionYear) !== -1) {
return true
}
this.addLog(`${info.versionYear ? 'unsupported' : 'unknown'} version "${info.version}" found at "${info.path}"`)
return false
})
if (versionYear === 2017) {
return 'v141'
} else if (versionYear === 2019) {
return 'v142'
} else if (versionYear === 2022) {
return 'v143'
}
this.log.silly('- invalid versionYear:', versionYear)
return null
}
// Sort to place newer versions first
vsInfo.sort((a, b) => b.versionYear - a.versionYear)
// Helper - process Windows SDK information
getSDK (info) {
const win8SDK = 'Microsoft.VisualStudio.Component.Windows81SDK'
const win10SDKPrefix = 'Microsoft.VisualStudio.Component.Windows10SDK.'
const win11SDKPrefix = 'Microsoft.VisualStudio.Component.Windows11SDK.'
for (let i = 0; i < vsInfo.length; ++i) {
const info = vsInfo[i]
this.addLog(`checking VS${info.versionYear} (${info.version}) found ` + `at:\n"${info.path}"`)
let Win10or11SDKVer = 0
info.packages.forEach((pkg) => {
if (!pkg.startsWith(win10SDKPrefix) && !pkg.startsWith(win11SDKPrefix)) {
return
}
const parts = pkg.split('.')
if (parts.length > 5 && parts[5] !== 'Desktop') {
this.log.silly('- ignoring non-Desktop Win10/11SDK:', pkg)
return
}
const foundSdkVer = parseInt(parts[4], 10)
if (isNaN(foundSdkVer)) {
// Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb
this.log.silly('- failed to parse Win10/11SDK number:', pkg)
return
}
this.log.silly('- found Win10/11SDK:', foundSdkVer)
Win10or11SDKVer = Math.max(Win10or11SDKVer, foundSdkVer)
})
if (info.msBuild) {
this.addLog('- found "Visual Studio C++ core features"')
} else {
this.addLog('- "Visual Studio C++ core features" missing')
continue
}
if (Win10or11SDKVer !== 0) {
return `10.0.${Win10or11SDKVer}.0`
} else if (info.packages.indexOf(win8SDK) !== -1) {
this.log.silly('- found Win8SDK')
return '8.1'
}
return null
}
if (info.toolset) {
this.addLog(`- found VC++ toolset: ${info.toolset}`)
} else {
this.addLog('- missing any VC++ toolset')
continue
}
// Find an installation of Visual Studio 2015 to use
async findVisualStudio2015 () {
if (semver.gte(this.nodeSemver, "19.0.0")) {
this.addLog(
'not looking for VS2015 as it is only supported up to Node.js 18')
return null
}
return this.findOldVS({
version: '14.0',
versionMajor: 14,
versionMinor: 0,
versionYear: 2015,
toolset: 'v140'
})
}
if (info.sdk) {
this.addLog(`- found Windows SDK: ${info.sdk}`)
} else {
this.addLog('- missing any Windows SDK')
continue
}
// Find an installation of Visual Studio 2013 to use
async findVisualStudio2013 () {
if (semver.gte(this.nodeSemver, "9.0.0")) {
this.addLog(
'not looking for VS2013 as it is only supported up to Node.js 8')
return null
}
return this.findOldVS({
version: '12.0',
versionMajor: 12,
versionMinor: 0,
versionYear: 2013,
toolset: 'v120'
})
}
if (!this.checkConfigVersion(info.versionYear, info.path)) {
continue
}
// Helper - common code for VS2013 and VS2015
async findOldVS (info) {
const regVC7 = ['HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7',
'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7']
const regMSBuild = 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions'
return info
}
this.addLog(`looking for Visual Studio ${info.versionYear}`)
try {
let res = await this.regSearchKeys(regVC7, info.version, [])
const vsPath = path.resolve(res, '..')
this.addLog(`- found in "${vsPath}"`)
const msBuildRegOpts = process.arch === 'ia32' ? [] : ['/reg:32']
this.addLog('could not find a version of Visual Studio 2017 or newer to use')
return null
}
try {
res = await this.regSearchKeys([`${regMSBuild}\\${info.version}`], 'MSBuildToolsPath', msBuildRegOpts)
} catch (err) {
this.addLog('- could not find MSBuild in registry for this version')
return null
}
// Helper - process version information
getVersionInfo(info) {
const match = /^(\d+)\.(\d+)(?:\..*)?/.exec(info.version)
if (!match) {
this.log.silly('- failed to parse version:', info.version)
return {}
}
this.log.silly('- version match = %j', match)
const ret = {
version: info.version,
versionMajor: parseInt(match[1], 10),
versionMinor: parseInt(match[2], 10),
}
if (ret.versionMajor === 15) {
ret.versionYear = 2017
return ret
}
if (ret.versionMajor === 16) {
ret.versionYear = 2019
return ret
}
if (ret.versionMajor === 17) {
ret.versionYear = 2022
return ret
}
this.log.silly('- unsupported version:', ret.versionMajor)
return {}
}
const msBuild = path.join(res, 'MSBuild.exe')
this.addLog(`- MSBuild in "${msBuild}"`)
msBuildPathExists(path) {
return existsSync(path)
}
if (!this.checkConfigVersion(info.versionYear, vsPath)) {
return null
}
// Helper - process MSBuild information
getMSBuild(info, versionYear) {
const pkg = 'Microsoft.VisualStudio.VC.MSBuild.Base'
const msbuildPath = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'MSBuild.exe')
const msbuildPathArm64 = path.join(info.path, 'MSBuild', 'Current', 'Bin', 'arm64', 'MSBuild.exe')
if (info.packages.indexOf(pkg) !== -1) {
this.log.silly('- found VC.MSBuild.Base')
if (versionYear === 2017) {
return path.join(info.path, 'MSBuild', '15.0', 'Bin', 'MSBuild.exe')
}
if (versionYear === 2019) {
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) {
return msbuildPathArm64
} else {
return msbuildPath
}
}
}
/**
* Visual Studio 2022 doesn't have the MSBuild package.
* Support for compiling _on_ ARM64 was added in MSVC 14.32.31326,
* so let's leverage it if the user has an ARM64 device.
*/
if (process.arch === 'arm64' && this.msBuildPathExists(msbuildPathArm64)) {
return msbuildPathArm64
} else if (this.msBuildPathExists(msbuildPath)) {
return msbuildPath
}
return null
}
info.path = vsPath
info.msBuild = msBuild
info.sdk = null
return info
} catch (err) {
this.addLog('- not found')
return null
}
}
// Helper - process toolset information
getToolset(info, versionYear) {
const vcToolsArm64 = 'VC.Tools.ARM64'
const pkgArm64 = `Microsoft.VisualStudio.Component.${vcToolsArm64}`
const vcToolsX64 = 'VC.Tools.x86.x64'
const pkgX64 = `Microsoft.VisualStudio.Component.${vcToolsX64}`
const express = 'Microsoft.VisualStudio.WDExpress'
// After finding a usable version of Visual Studio:
// - add it to validVersions to be displayed at the end if a specific
// version was requested and not found;
// - check if this is the version that was requested.
// - check if this matches the Visual Studio Command Prompt
checkConfigVersion (versionYear, vsPath) {
this.validVersions.push(versionYear)
this.validVersions.push(vsPath)
if (process.arch === 'arm64' && info.packages.includes(pkgArm64)) {
this.log.silly(`- found ${vcToolsArm64}`)
} else if (info.packages.includes(pkgX64)) {
if (process.arch === 'arm64') {
this.addLog(
`- found ${vcToolsX64} on ARM64 platform. Expect less performance and/or link failure with ARM64 binary.`,
)
} else {
this.log.silly(`- found ${vcToolsX64}`)
}
} else if (info.packages.includes(express)) {
this.log.silly('- found Visual Studio Express (looking for toolset)')
} else {
return null
}
if (this.configVersionYear && this.configVersionYear !== versionYear) {
this.addLog('- msvs_version does not match this version')
return false
}
if (this.configPath &&
path.relative(this.configPath, vsPath) !== '') {
this.addLog('- msvs_version does not point to this installation')
return false
}
if (this.envVcInstallDir &&
path.relative(this.envVcInstallDir, vsPath) !== '') {
this.addLog('- does not match this Visual Studio Command Prompt')
return false
}
if (versionYear === 2017) {
return 'v141'
} else if (versionYear === 2019) {
return 'v142'
} else if (versionYear === 2022) {
return 'v143'
}
this.log.silly('- invalid versionYear:', versionYear)
return null
}
return true
}
// Helper - process Windows SDK information
getSDK(info) {
const win8SDK = 'Microsoft.VisualStudio.Component.Windows81SDK'
const win10SDKPrefix = 'Microsoft.VisualStudio.Component.Windows10SDK.'
const win11SDKPrefix = 'Microsoft.VisualStudio.Component.Windows11SDK.'
let Win10or11SDKVer = 0
info.packages.forEach((pkg) => {
if (!pkg.startsWith(win10SDKPrefix) && !pkg.startsWith(win11SDKPrefix)) {
return
}
const parts = pkg.split('.')
if (parts.length > 5 && parts[5] !== 'Desktop') {
this.log.silly('- ignoring non-Desktop Win10/11SDK:', pkg)
return
}
const foundSdkVer = parseInt(parts[4], 10)
if (isNaN(foundSdkVer)) {
// Microsoft.VisualStudio.Component.Windows10SDK.IpOverUsb
this.log.silly('- failed to parse Win10/11SDK number:', pkg)
return
}
this.log.silly('- found Win10/11SDK:', foundSdkVer)
Win10or11SDKVer = Math.max(Win10or11SDKVer, foundSdkVer)
})
if (Win10or11SDKVer !== 0) {
return `10.0.${Win10or11SDKVer}.0`
} else if (info.packages.indexOf(win8SDK) !== -1) {
this.log.silly('- found Win8SDK')
return '8.1'
}
return null
}
// Find an installation of Visual Studio 2015 to use
async findVisualStudio2015() {
if (semver.gte(this.nodeSemver, '19.0.0')) {
this.addLog('not looking for VS2015 as it is only supported up to Node.js 18')
return null
}
return this.findOldVS({
version: '14.0',
versionMajor: 14,
versionMinor: 0,
versionYear: 2015,
toolset: 'v140',
})
}
// Find an installation of Visual Studio 2013 to use
async findVisualStudio2013() {
if (semver.gte(this.nodeSemver, '9.0.0')) {
this.addLog('not looking for VS2013 as it is only supported up to Node.js 8')
return null
}
return this.findOldVS({
version: '12.0',
versionMajor: 12,
versionMinor: 0,
versionYear: 2013,
toolset: 'v120',
})
}
// Helper - common code for VS2013 and VS2015
async findOldVS(info) {
const regVC7 = [
'HKLM\\Software\\Microsoft\\VisualStudio\\SxS\\VC7',
'HKLM\\Software\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\VC7',
]
const regMSBuild = 'HKLM\\Software\\Microsoft\\MSBuild\\ToolsVersions'
this.addLog(`looking for Visual Studio ${info.versionYear}`)
try {
let res = await this.regSearchKeys(regVC7, info.version, [])
const vsPath = path.resolve(res, '..')
this.addLog(`- found in "${vsPath}"`)
const msBuildRegOpts = process.arch === 'ia32' ? [] : ['/reg:32']
try {
res = await this.regSearchKeys([`${regMSBuild}\\${info.version}`], 'MSBuildToolsPath', msBuildRegOpts)
} catch (err) {
this.addLog('- could not find MSBuild in registry for this version')
return null
}
const msBuild = path.join(res, 'MSBuild.exe')
this.addLog(`- MSBuild in "${msBuild}"`)
if (!this.checkConfigVersion(info.versionYear, vsPath)) {
return null
}
info.path = vsPath
info.msBuild = msBuild
info.sdk = null
return info
} catch (err) {
this.addLog('- not found')
return null
}
}
// After finding a usable version of Visual Studio:
// - add it to validVersions to be displayed at the end if a specific
// version was requested and not found;
// - check if this is the version that was requested.
// - check if this matches the Visual Studio Command Prompt
checkConfigVersion(versionYear, vsPath) {
this.validVersions.push(versionYear)
this.validVersions.push(vsPath)
if (this.configVersionYear && this.configVersionYear !== versionYear) {
this.addLog('- msvs_version does not match this version')
return false
}
if (this.configPath && path.relative(this.configPath, vsPath) !== '') {
this.addLog('- msvs_version does not point to this installation')
return false
}
if (this.envVcInstallDir && path.relative(this.envVcInstallDir, vsPath) !== '') {
this.addLog('- does not match this Visual Studio Command Prompt')
return false
}
return true
}
async execFile(exec, args) {
return await execFile(exec, args, { encoding: 'utf8' })
}
}
module.exports = VisualStudioFinder
module.exports = VisualStudioFinder

@@ -7,66 +7,65 @@ 'use strict'

const execFile = async (...args) =>
new Promise((resolve) => {
const child = cp.execFile(...args, (...a) => resolve(a))
child.stdin.end()
})
const execFile = async (...args) => new Promise((resolve) => {
const child = cp.execFile(...args, (...a) => resolve(a))
child.stdin.end()
})
function logWithPrefix (log, prefix) {
function setPrefix (logFunction) {
return (...args) => logFunction.apply(null, [ prefix, ...args ]) // eslint-disable-line
}
return {
silly: setPrefix(log.silly),
verbose: setPrefix(log.verbose),
info: setPrefix(log.info),
warn: setPrefix(log.warn),
error: setPrefix(log.error)
}
function logWithPrefix(log, prefix) {
function setPrefix(logFunction) {
return (...args) => logFunction.apply(null, [prefix, ...args]) // eslint-disable-line
}
return {
silly: setPrefix(log.silly),
verbose: setPrefix(log.verbose),
info: setPrefix(log.info),
warn: setPrefix(log.warn),
error: setPrefix(log.error),
}
}
async function regGetValue (key, value, addOpts) {
const outReValue = value.replace(/\W/g, '.')
const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im')
const reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe')
const regArgs = ['query', key, '/v', value].concat(addOpts)
async function regGetValue(key, value, addOpts) {
const outReValue = value.replace(/\W/g, '.')
const outRe = new RegExp(`^\\s+${outReValue}\\s+REG_\\w+\\s+(\\S.*)$`, 'im')
const reg = path.join(process.env.SystemRoot, 'System32', 'reg.exe')
const regArgs = ['query', key, '/v', value].concat(addOpts)
log.silly('reg', 'running', reg, regArgs)
const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' })
log.silly('reg', 'running', reg, regArgs)
const [err, stdout, stderr] = await execFile(reg, regArgs, { encoding: 'utf8' })
log.silly('reg', 'reg.exe stdout = %j', stdout)
if (err || stderr.trim() !== '') {
log.silly('reg', 'reg.exe err = %j', err && (err.stack || err))
log.silly('reg', 'reg.exe stderr = %j', stderr)
if (err) {
throw err
}
throw new Error(stderr)
}
log.silly('reg', 'reg.exe stdout = %j', stdout)
if (err || stderr.trim() !== '') {
log.silly('reg', 'reg.exe err = %j', err && (err.stack || err))
log.silly('reg', 'reg.exe stderr = %j', stderr)
if (err) {
throw err
}
throw new Error(stderr)
}
const result = outRe.exec(stdout)
if (!result) {
log.silly('reg', 'error parsing stdout')
throw new Error('Could not parse output of reg.exe')
}
const result = outRe.exec(stdout)
if (!result) {
log.silly('reg', 'error parsing stdout')
throw new Error('Could not parse output of reg.exe')
}
log.silly('reg', 'found: %j', result[1])
return result[1]
log.silly('reg', 'found: %j', result[1])
return result[1]
}
async function regSearchKeys (keys, value, addOpts) {
for (const key of keys) {
try {
return await regGetValue(key, value, addOpts)
} catch {
continue
}
}
async function regSearchKeys(keys, value, addOpts) {
for (const key of keys) {
try {
return await regGetValue(key, value, addOpts)
} catch {
continue
}
}
}
module.exports = {
logWithPrefix: logWithPrefix,
regGetValue: regGetValue,
regSearchKeys: regSearchKeys,
execFile: execFile
}
logWithPrefix: logWithPrefix,
regGetValue: regGetValue,
regSearchKeys: regSearchKeys,
execFile: execFile,
}

@@ -1,12 +0,12 @@

"use strict";
'use strict'
module.exports = {
BuildSystem: require("./buildSystem"),
CMLog: require("./cmLog"),
environment: require("./environment"),
TargetOptions: require("./targetOptions"),
Dist: require("./dist"),
CMake: require("./cMake"),
downloader: require("./downloader"),
Toolset: require("./toolset"),
};
BuildSystem: require('./buildSystem'),
CMLog: require('./cmLog'),
environment: require('./environment'),
TargetOptions: require('./targetOptions'),
Dist: require('./dist'),
CMake: require('./cMake'),
downloader: require('./downloader'),
Toolset: require('./toolset'),
}

@@ -1,65 +0,63 @@

"use strict";
const fs = require("fs-extra");
const path = require("path");
'use strict'
const fs = require('fs-extra')
const path = require('path')
const isNANModule = async function (dir) {
const h = path.join(dir, "nan.h");
try {
const stat = await fs.stat(h);
return stat.isFile();
}
catch (e) {
return false;
}
};
const h = path.join(dir, 'nan.h')
try {
const stat = await fs.stat(h)
return stat.isFile()
} catch (e) {
return false
}
}
async function isNodeJSProject (dir) {
const pjson = path.join(dir, "package.json");
const node_modules = path.join(dir, "node_modules");
try {
let stat = await fs.stat(pjson);
if (stat.isFile()) {
return true;
}
stat = await fs.stat(node_modules);
if (stat.isDirectory()) {
return true;
}
}
catch (e) {
// Ignore
}
return false;
};
async function isNodeJSProject(dir) {
const pjson = path.join(dir, 'package.json')
const node_modules = path.join(dir, 'node_modules')
try {
let stat = await fs.stat(pjson)
if (stat.isFile()) {
return true
}
stat = await fs.stat(node_modules)
if (stat.isDirectory()) {
return true
}
} catch (e) {
// Ignore
}
return false
}
const locateNAN = module.exports = async function (projectRoot) {
if (locateNAN.__projectRoot) {
// Override for unit tests
projectRoot = locateNAN.__projectRoot;
}
const locateNAN = (module.exports = async function (projectRoot) {
if (locateNAN.__projectRoot) {
// Override for unit tests
projectRoot = locateNAN.__projectRoot
}
let result = await isNodeJSProject(projectRoot);
if (!result) {
return null;
}
let result = await isNodeJSProject(projectRoot)
if (!result) {
return null
}
const nanModulePath = path.join(projectRoot, "node_modules", "nan");
result = await isNANModule(nanModulePath);
if (result) {
return nanModulePath;
}
const nanModulePath = path.join(projectRoot, 'node_modules', 'nan')
result = await isNANModule(nanModulePath)
if (result) {
return nanModulePath
}
// Goto upper level:
return await locateNAN(goUp(projectRoot));
};
// Goto upper level:
return await locateNAN(goUp(projectRoot))
})
function goUp(dir) {
const items = dir.split(path.sep);
const scopeItem = items[items.length - 2];
if (scopeItem && scopeItem[0] === "@") {
// skip scope
dir = path.join(dir, "..");
}
dir = path.join(dir, "..", "..");
return path.normalize(dir);
const items = dir.split(path.sep)
const scopeItem = items[items.length - 2]
if (scopeItem && scopeItem[0] === '@') {
// skip scope
dir = path.join(dir, '..')
}
dir = path.join(dir, '..', '..')
return path.normalize(dir)
}

@@ -1,18 +0,18 @@

"use strict";
const path = require("path");
'use strict'
const path = require('path')
const locateNodeApi = module.exports = async function (projectRoot) {
if (locateNodeApi.__projectRoot) {
// Override for unit tests
projectRoot = locateNodeApi.__projectRoot;
}
const locateNodeApi = (module.exports = async function (projectRoot) {
if (locateNodeApi.__projectRoot) {
// Override for unit tests
projectRoot = locateNodeApi.__projectRoot
}
try {
const tmpRequire = require('module').createRequire(path.join(projectRoot, 'package.json'))
const inc = tmpRequire('node-addon-api')
return inc.include.replace(/"/g, '')
} catch (e) {
// It most likely wasn't found
return null;
}
};
try {
const tmpRequire = require('module').createRequire(path.join(projectRoot, 'package.json'))
const inc = tmpRequire('node-addon-api')
return inc.include.replace(/"/g, '')
} catch (e) {
// It most likely wasn't found
return null
}
})

@@ -1,31 +0,31 @@

"use strict";
'use strict'
function getNpmConfig() {
const npmOptions = {};
const npmConfigPrefix = 'npm_config_';
Object.keys(process.env).forEach(function (name) {
if (name.indexOf(npmConfigPrefix) !== 0) {
return;
}
const value = process.env[name];
name = name.substring(npmConfigPrefix.length);
if (name) {
npmOptions[name] = value;
}
}, this);
const npmOptions = {}
const npmConfigPrefix = 'npm_config_'
Object.keys(process.env).forEach(function (name) {
if (name.indexOf(npmConfigPrefix) !== 0) {
return
}
const value = process.env[name]
name = name.substring(npmConfigPrefix.length)
if (name) {
npmOptions[name] = value
}
}, this)
return npmOptions;
return npmOptions
}
module.exports = function (log) {
log.verbose("CFG", "Looking for NPM config.");
const options = getNpmConfig();
log.verbose('CFG', 'Looking for NPM config.')
const options = getNpmConfig()
if (options) {
log.silly("CFG", "NPM options:", options);
}else {
log.verbose("CFG", "There are no NPM options available.");
}
if (options) {
log.silly('CFG', 'NPM options:', options)
} else {
log.verbose('CFG', 'There are no NPM options available.')
}
return options;
};
return options
}

@@ -1,55 +0,53 @@

"use strict";
const spawn = require("child_process").spawn;
const execFile = require("child_process").execFile;
'use strict'
const spawn = require('child_process').spawn
const execFile = require('child_process').execFile
const processHelpers = {
run: function (command, options) {
if (!options) options = {};
run: function (command, options) {
if (!options) options = {}
return new Promise(function (resolve, reject) {
const env = Object.assign({}, process.env);
if (env.Path && env.PATH) {
if(env.Path !== env.PATH) {
env.PATH = env.Path + ';' + env.PATH;
}
delete env.Path;
}
const child = spawn(command[0], command.slice(1), {
stdio: options.silent ? "ignore" : "inherit",
env
});
let ended = false;
child.on("error", function (e) {
if (!ended) {
reject(e);
ended = true;
}
});
child.on("exit", function (code, signal) {
if (!ended) {
if (code === 0) {
resolve();
}
else {
reject(new Error("Process terminated: " + code || signal));
}
ended = true;
}
});
});
},
execFile: function(command) {
return new Promise(function (resolve, reject) {
execFile(command[0], command.slice(1), function (err, stdout, stderr) {
if (err) {
reject(new Error(err.message + "\n" + (stdout || stderr)));
}
else {
resolve(stdout);
}
});
});
}
};
return new Promise(function (resolve, reject) {
const env = Object.assign({}, process.env)
if (env.Path && env.PATH) {
if (env.Path !== env.PATH) {
env.PATH = env.Path + ';' + env.PATH
}
delete env.Path
}
const child = spawn(command[0], command.slice(1), {
stdio: options.silent ? 'ignore' : 'inherit',
env,
})
let ended = false
child.on('error', function (e) {
if (!ended) {
reject(e)
ended = true
}
})
child.on('exit', function (code, signal) {
if (!ended) {
if (code === 0) {
resolve()
} else {
reject(new Error('Process terminated: ' + code || signal))
}
ended = true
}
})
})
},
execFile: function (command) {
return new Promise(function (resolve, reject) {
execFile(command[0], command.slice(1), function (err, stdout, stderr) {
if (err) {
reject(new Error(err.message + '\n' + (stdout || stderr)))
} else {
resolve(stdout)
}
})
})
},
}
module.exports = processHelpers;
module.exports = processHelpers

@@ -1,86 +0,95 @@

"use strict";
const assert = require("assert");
const semver = require("semver");
const isPlainObject = require("lodash.isplainobject");
'use strict'
const assert = require('assert')
const semver = require('semver')
const NODE_MIRROR = process.env.NVM_NODEJS_ORG_MIRROR || "https://nodejs.org/dist";
const ELECTRON_MIRROR = process.env.ELECTRON_MIRROR || "https://artifacts.electronjs.org/headers/dist";
const NODE_MIRROR = process.env.NVM_NODEJS_ORG_MIRROR || 'https://nodejs.org/dist'
const ELECTRON_MIRROR = process.env.ELECTRON_MIRROR || 'https://artifacts.electronjs.org/headers/dist'
const runtimePaths = {
node: function (targetOptions) {
if (semver.lt(targetOptions.runtimeVersion, "4.0.0")) {
return {
externalPath: NODE_MIRROR + "/v" + targetOptions.runtimeVersion + "/",
winLibs: [{
dir: targetOptions.isX64 ? "x64" : "",
name: targetOptions.runtime + ".lib"
}],
tarPath: targetOptions.runtime + "-v" + targetOptions.runtimeVersion + ".tar.gz",
headerOnly: false
};
}
else {
return {
externalPath: NODE_MIRROR + "/v" + targetOptions.runtimeVersion + "/",
winLibs: [{
dir: targetOptions.isX64 ? "win-x64" : "win-x86",
name: targetOptions.runtime + ".lib"
}],
tarPath: targetOptions.runtime + "-v" + targetOptions.runtimeVersion + "-headers.tar.gz",
headerOnly: true
};
}
},
nw: function (targetOptions) {
if (semver.gte(targetOptions.runtimeVersion, "0.13.0")) {
return {
externalPath: "https://node-webkit.s3.amazonaws.com/v" + targetOptions.runtimeVersion + "/",
winLibs: [
{
dir: targetOptions.isX64 ? "x64" : "",
name: targetOptions.runtime + ".lib"
},
{
dir: targetOptions.isX64 ? "x64" : "",
name: "node.lib"
}
],
tarPath: "nw-headers-v" + targetOptions.runtimeVersion + ".tar.gz",
headerOnly: false
};
}
return {
externalPath: "https://node-webkit.s3.amazonaws.com/v" + targetOptions.runtimeVersion + "/",
winLibs: [{
dir: targetOptions.isX64 ? "x64" : "",
name: targetOptions.runtime + ".lib"
}],
tarPath: "nw-headers-v" + targetOptions.runtimeVersion + ".tar.gz",
headerOnly: false
};
},
electron: function (targetOptions) {
return {
externalPath: ELECTRON_MIRROR + "/v" + targetOptions.runtimeVersion + "/",
winLibs: [{
dir: targetOptions.isX64 ? "x64" : "",
name: "node.lib"
}],
tarPath: "node" + "-v" + targetOptions.runtimeVersion + ".tar.gz",
headerOnly: semver.gte(targetOptions.runtimeVersion, '4.0.0-alpha')
};
},
get: function (targetOptions) {
assert(targetOptions && typeof targetOptions === 'object');
node: function (targetOptions) {
if (semver.lt(targetOptions.runtimeVersion, '4.0.0')) {
return {
externalPath: NODE_MIRROR + '/v' + targetOptions.runtimeVersion + '/',
winLibs: [
{
dir: targetOptions.isX64 ? 'x64' : '',
name: targetOptions.runtime + '.lib',
},
],
tarPath: targetOptions.runtime + '-v' + targetOptions.runtimeVersion + '.tar.gz',
headerOnly: false,
}
} else {
return {
externalPath: NODE_MIRROR + '/v' + targetOptions.runtimeVersion + '/',
winLibs: [
{
dir: targetOptions.isArm64 ? 'win-arm64' : targetOptions.isX64 ? 'win-x64' : 'win-x86',
name: targetOptions.runtime + '.lib',
},
],
tarPath: targetOptions.runtime + '-v' + targetOptions.runtimeVersion + '-headers.tar.gz',
headerOnly: true,
}
}
},
nw: function (targetOptions) {
if (semver.gte(targetOptions.runtimeVersion, '0.13.0')) {
return {
externalPath: 'https://node-webkit.s3.amazonaws.com/v' + targetOptions.runtimeVersion + '/',
winLibs: [
{
dir: targetOptions.isX64 ? 'x64' : '',
name: targetOptions.runtime + '.lib',
},
{
dir: targetOptions.isX64 ? 'x64' : '',
name: 'node.lib',
},
],
tarPath: 'nw-headers-v' + targetOptions.runtimeVersion + '.tar.gz',
headerOnly: false,
}
}
return {
externalPath: 'https://node-webkit.s3.amazonaws.com/v' + targetOptions.runtimeVersion + '/',
winLibs: [
{
dir: targetOptions.isX64 ? 'x64' : '',
name: targetOptions.runtime + '.lib',
},
],
tarPath: 'nw-headers-v' + targetOptions.runtimeVersion + '.tar.gz',
headerOnly: false,
}
},
electron: function (targetOptions) {
return {
externalPath: ELECTRON_MIRROR + '/v' + targetOptions.runtimeVersion + '/',
winLibs: [
{
dir: targetOptions.isArm64 ? 'arm64' : targetOptions.isX64 ? 'x64' : '',
name: 'node.lib',
},
],
tarPath: 'node' + '-v' + targetOptions.runtimeVersion + '.tar.gz',
headerOnly: semver.gte(targetOptions.runtimeVersion, '4.0.0-alpha'),
}
},
get: function (targetOptions) {
assert(targetOptions && typeof targetOptions === 'object')
const runtime = targetOptions.runtime;
const func = runtimePaths[runtime];
let paths;
if (typeof func === 'function' && isPlainObject(paths = func(targetOptions))) {
return paths;
}
throw new Error("Unknown runtime: " + runtime);
}
};
const runtime = targetOptions.runtime
const func = runtimePaths[runtime]
let paths
if (typeof func === 'function') {
paths = func(targetOptions)
if (paths && typeof paths === 'object') {
return paths
}
}
throw new Error('Unknown runtime: ' + runtime)
},
}
module.exports = runtimePaths;
module.exports = runtimePaths

@@ -1,42 +0,33 @@

"use strict";
'use strict'
const environment = require("./environment");
const environment = require('./environment')
function TargetOptions(options) {
this.options = options || {};
class TargetOptions {
get arch() {
return this.options.arch || environment.arch
}
get isX86() {
return this.arch === 'ia32' || this.arch === 'x86'
}
get isX64() {
return this.arch === 'x64'
}
get isArm() {
return this.arch === 'arm'
}
get isArm64() {
return this.arch === 'arm64'
}
get runtime() {
return this.options.runtime || environment.runtime
}
get runtimeVersion() {
return this.options.runtimeVersion || environment.runtimeVersion
}
constructor(options) {
this.options = options || {}
}
}
Object.defineProperties(TargetOptions.prototype, {
arch: {
get: function () {
return this.options.arch || environment.arch;
}
},
isX86: {
get: function () {
return this.arch === "ia32" || this.arch === "x86";
}
},
isX64: {
get: function () {
return this.arch === "x64";
}
},
isArm: {
get: function () {
return this.arch === "arm";
}
},
runtime: {
get: function () {
return this.options.runtime || environment.runtime;
}
},
runtimeVersion: {
get: function () {
return this.options.runtimeVersion || environment.runtimeVersion;
}
}
});
module.exports = TargetOptions;
module.exports = TargetOptions

@@ -1,226 +0,224 @@

"use strict";
const TargetOptions = require("./targetOptions");
const environment = require("./environment");
const assert = require("assert");
const CMLog = require("./cmLog");
const util = require('util')
'use strict'
const TargetOptions = require('./targetOptions')
const environment = require('./environment')
const assert = require('assert')
const CMLog = require('./cmLog')
const { findVisualStudio } = environment.isWin ? require('./import/find-visualstudio') : {}
class Toolset {
constructor(options) {
this.options = options || {}
this.targetOptions = new TargetOptions(this.options)
this.generator = options.generator
this.toolset = options.toolset
this.platform = options.platform
this.target = options.target
this.cCompilerPath = options.cCompilerPath
this.cppCompilerPath = options.cppCompilerPath
this.compilerFlags = []
this.linkerFlags = []
this.makePath = null
this.log = new CMLog(this.options)
this._initialized = false
}
async initialize(install) {
if (!this._initialized) {
if (environment.isWin) {
await this.initializeWin(install)
} else {
this.initializePosix(install)
}
this._initialized = true
}
}
initializePosix(install) {
if (!this.cCompilerPath || !this.cppCompilerPath) {
// 1: Compiler
if (!environment.isGPPAvailable && !environment.isClangAvailable) {
if (environment.isOSX) {
throw new Error(
"C++ Compiler toolset is not available. Install Xcode Commandline Tools from Apple Dev Center, or install Clang with homebrew by invoking: 'brew install llvm --with-clang --with-asan'.",
)
} else {
throw new Error(
"C++ Compiler toolset is not available. Install proper compiler toolset with your package manager, eg. 'sudo apt-get install g++'.",
)
}
}
function Toolset(options) {
this.options = options || {};
this.targetOptions = new TargetOptions(this.options);
this.generator = options.generator;
this.toolset = options.toolset;
this.platform = options.platform;
this.target = options.target;
this.cCompilerPath = options.cCompilerPath;
this.cppCompilerPath = options.cppCompilerPath;
this.compilerFlags = [];
this.linkerFlags = [];
this.makePath = null;
this.log = new CMLog(this.options);
this._initialized = false;
}
if (this.options.preferClang && environment.isClangAvailable) {
if (install) {
this.log.info('TOOL', 'Using clang++ compiler, because preferClang option is set, and clang++ is available.')
}
this.cppCompilerPath = this.cppCompilerPath || 'clang++'
this.cCompilerPath = this.cCompilerPath || 'clang'
} else if (this.options.preferGnu && environment.isGPPAvailable) {
if (install) {
this.log.info('TOOL', 'Using g++ compiler, because preferGnu option is set, and g++ is available.')
}
this.cppCompilerPath = this.cppCompilerPath || 'g++'
this.cCompilerPath = this.cCompilerPath || 'gcc'
}
}
// if it's already set because of options...
if (this.generator) {
if (install) {
this.log.info('TOOL', 'Using ' + this.generator + ' generator, as specified from commandline.')
}
}
Toolset.prototype.initialize = async function (install) {
if (!this._initialized) {
if (environment.isWin) {
await this.initializeWin(install);
}
else {
this.initializePosix(install);
}
this._initialized = true;
}
};
// 2: Generator
else if (environment.isOSX) {
if (this.options.preferXcode) {
if (install) {
this.log.info('TOOL', 'Using Xcode generator, because preferXcode option is set.')
}
this.generator = 'Xcode'
} else if (this.options.preferMake && environment.isMakeAvailable) {
if (install) {
this.log.info(
'TOOL',
'Using Unix Makefiles generator, because preferMake option is set, and make is available.',
)
}
this.generator = 'Unix Makefiles'
} else if (environment.isNinjaAvailable) {
if (install) {
this.log.info('TOOL', 'Using Ninja generator, because ninja is available.')
}
this.generator = 'Ninja'
} else {
if (install) {
this.log.info('TOOL', 'Using Unix Makefiles generator.')
}
this.generator = 'Unix Makefiles'
}
} else {
if (this.options.preferMake && environment.isMakeAvailable) {
if (install) {
this.log.info(
'TOOL',
'Using Unix Makefiles generator, because preferMake option is set, and make is available.',
)
}
this.generator = 'Unix Makefiles'
} else if (environment.isNinjaAvailable) {
if (install) {
this.log.info('TOOL', 'Using Ninja generator, because ninja is available.')
}
this.generator = 'Ninja'
} else {
if (install) {
this.log.info('TOOL', 'Using Unix Makefiles generator.')
}
this.generator = 'Unix Makefiles'
}
}
Toolset.prototype.initializePosix = function (install) {
if (!this.cCompilerPath || !this.cppCompilerPath) {
// 1: Compiler
if (!environment.isGPPAvailable && !environment.isClangAvailable) {
if (environment.isOSX) {
throw new Error("C++ Compiler toolset is not available. Install Xcode Commandline Tools from Apple Dev Center, or install Clang with homebrew by invoking: 'brew install llvm --with-clang --with-asan'.");
}
else {
throw new Error("C++ Compiler toolset is not available. Install proper compiler toolset with your package manager, eg. 'sudo apt-get install g++'.");
}
}
// 3: Flags
if (environment.isOSX) {
if (install) {
this.log.verbose('TOOL', 'Setting default OSX compiler flags.')
}
if (this.options.preferClang && environment.isClangAvailable) {
if (install) {
this.log.info("TOOL", "Using clang++ compiler, because preferClang option is set, and clang++ is available.");
}
this.cppCompilerPath = this.cppCompilerPath || "clang++";
this.cCompilerPath = this.cCompilerPath || "clang";
}
else if (this.options.preferGnu && environment.isGPPAvailable) {
if (install) {
this.log.info("TOOL", "Using g++ compiler, because preferGnu option is set, and g++ is available.");
}
this.cppCompilerPath = this.cppCompilerPath || "g++";
this.cCompilerPath = this.cCompilerPath || "gcc";
}
}
// if it's already set because of options...
if (this.generator) {
if (install) {
this.log.info("TOOL", "Using " + this.generator + " generator, as specified from commandline.");
}
}
// 2: Generator
else if (environment.isOSX) {
if (this.options.preferXcode) {
if (install) {
this.log.info("TOOL", "Using Xcode generator, because preferXcode option is set.");
}
this.generator = "Xcode";
}
else if (this.options.preferMake && environment.isMakeAvailable) {
if (install) {
this.log.info("TOOL", "Using Unix Makefiles generator, because preferMake option is set, and make is available.");
}
this.generator = "Unix Makefiles";
}
else if (environment.isNinjaAvailable) {
if (install) {
this.log.info("TOOL", "Using Ninja generator, because ninja is available.");
}
this.generator = "Ninja";
}
else {
if (install) {
this.log.info("TOOL", "Using Unix Makefiles generator.");
}
this.generator = "Unix Makefiles";
}
}
else {
if (this.options.preferMake && environment.isMakeAvailable) {
if (install) {
this.log.info("TOOL", "Using Unix Makefiles generator, because preferMake option is set, and make is available.");
}
this.generator = "Unix Makefiles";
}
else if (environment.isNinjaAvailable) {
if (install) {
this.log.info("TOOL", "Using Ninja generator, because ninja is available.");
}
this.generator = "Ninja";
}
else {
if (install) {
this.log.info("TOOL", "Using Unix Makefiles generator.");
}
this.generator = "Unix Makefiles";
}
}
this.compilerFlags.push('-D_DARWIN_USE_64_BIT_INODE=1')
this.compilerFlags.push('-D_LARGEFILE_SOURCE')
this.compilerFlags.push('-D_FILE_OFFSET_BITS=64')
this.linkerFlags.push('-undefined dynamic_lookup')
}
// 3: Flags
if (environment.isOSX) {
if (install) {
this.log.verbose("TOOL", "Setting default OSX compiler flags.");
}
this.compilerFlags.push('-DBUILDING_NODE_EXTENSION')
this.compilerFlags.push("-D_DARWIN_USE_64_BIT_INODE=1");
this.compilerFlags.push("-D_LARGEFILE_SOURCE");
this.compilerFlags.push("-D_FILE_OFFSET_BITS=64");
this.linkerFlags.push("-undefined dynamic_lookup");
}
this.compilerFlags.push("-DBUILDING_NODE_EXTENSION");
// 4: Build target
if (this.options.target) {
this.log.info('TOOL', 'Building only the ' + this.options.target + ' target, as specified from the command line.')
}
}
async initializeWin(install) {
if (!this.generator) {
const foundVsInfo = await this._getTopSupportedVisualStudioGenerator()
if (foundVsInfo) {
if (install) {
this.log.info('TOOL', `Using ${foundVsInfo.generator} generator.`)
}
this.generator = foundVsInfo.generator
// 4: Build target
if (this.options.target) {
this.log.info("TOOL", "Building only the " + this.options.target + " target, as specified from the command line.");
}
};
const isAboveVS16 = foundVsInfo.versionMajor >= 16
Toolset.prototype.initializeWin = async function (install) {
if (!this.generator) {
const foundVsInfo = await this._getTopSupportedVisualStudioGenerator();
if (foundVsInfo) {
if (install) {
this.log.info("TOOL", `Using ${foundVsInfo.generator} generator.`);
}
this.generator = foundVsInfo.generator;
// The CMake Visual Studio Generator does not support the Win64 or ARM suffix on
// the generator name. Instead the generator platform must be set explicitly via
// the platform parameter
if (!this.platform && isAboveVS16) {
switch (this.targetOptions.arch) {
case 'ia32':
case 'x86':
this.platform = 'Win32'
break
case 'x64':
this.platform = 'x64'
break
case 'arm':
this.platform = 'ARM'
break
case 'arm64':
this.platform = 'ARM64'
break
default:
this.log.warn('TOOL', 'Unknown NodeJS architecture: ' + this.targetOptions.arch)
break
}
}
} else {
throw new Error('There is no Visual C++ compiler installed. Install Visual C++ Build Toolset or Visual Studio.')
}
} else {
// if it's already set because of options...
if (install) {
this.log.info('TOOL', 'Using ' + this.options.generator + ' generator, as specified from commandline.')
}
}
const isAboveVS16 = foundVsInfo.versionMajor >= 16;
this.linkerFlags.push('/DELAYLOAD:NODE.EXE')
// The CMake Visual Studio Generator does not support the Win64 or ARM suffix on
// the generator name. Instead the generator platform must be set explicitly via
// the platform parameter
if (!this.platform && isAboveVS16) {
switch(this.targetOptions.arch) {
case "ia32":
case "x86":
this.platform = "Win32";
break;
case "x64":
this.platform = "x64";
break;
case "arm":
this.platform = "ARM";
break;
case "arm64":
this.platform = "ARM64";
break;
default:
this.log.warn("TOOL", "Unknown NodeJS architecture: " + this.targetOptions.arch);
break;
}
}
} else {
throw new Error("There is no Visual C++ compiler installed. Install Visual C++ Build Toolset or Visual Studio.");
}
} else {
// if it's already set because of options...
if (install) {
this.log.info("TOOL", "Using " + this.options.generator + " generator, as specified from commandline.");
}
}
if (this.targetOptions.isX86) {
if (install) {
this.log.verbose('TOOL', 'Setting SAFESEH:NO linker flag.')
}
this.linkerFlags.push('/SAFESEH:NO')
}
}
async _getTopSupportedVisualStudioGenerator() {
const CMake = require('./cMake')
assert(environment.isWin)
this.linkerFlags.push("/DELAYLOAD:NODE.EXE");
const selectedVs = await findVisualStudio(environment.runtimeVersion, this.options.msvsVersion)
if (!selectedVs) return null
if (this.targetOptions.isX86) {
if (install) {
this.log.verbose("TOOL", "Setting SAFESEH:NO linker flag.");
}
this.linkerFlags.push("/SAFESEH:NO");
}
};
const list = await CMake.getGenerators(this.options, this.log)
for (const gen of list) {
const found = gen.startsWith(`Visual Studio ${selectedVs.versionMajor}`)
if (!found) {
continue
}
Toolset.prototype._getTopSupportedVisualStudioGenerator = async function () {
const CMake = require("./cMake");
assert(environment.isWin);
// unlike previous versions "Visual Studio 16 2019" and onwards don't end with arch name
const isAboveVS16 = selectedVs.versionMajor >= 16
if (!isAboveVS16) {
const is64Bit = gen.endsWith('Win64')
if ((this.targetOptions.isX86 && is64Bit) || (this.targetOptions.isX64 && !is64Bit)) {
continue
}
}
const selectedVs = await findVisualStudio(environment.runtimeVersion, this.options.msvsVersion)
if (!selectedVs) return null;
return {
...selectedVs,
generator: gen,
}
}
const list = await CMake.getGenerators(this.options, this.log);
for (const gen of list) {
const found = gen.startsWith(`Visual Studio ${selectedVs.versionMajor}`)
if (!found) {
continue;
}
// Nothing matched
return null
}
}
// unlike previous versions "Visual Studio 16 2019" and onwards don't end with arch name
const isAboveVS16 = selectedVs.versionMajor >= 16;
if (!isAboveVS16) {
const is64Bit = gen.endsWith("Win64");
if ((this.targetOptions.isX86 && is64Bit) || (this.targetOptions.isX64 && !is64Bit)) {
continue;
}
}
return {
...selectedVs,
generator: gen
}
}
// Nothing matched
return null;
};
module.exports = Toolset;
module.exports = Toolset
{
"name": "cmake-js",
"description": "CMake.js - a Node.js native addon build tool",
"license": "MIT",
"keywords": [
"native",
"addon",
"module",
"c",
"c++",
"bindings",
"build",
"buildtools",
"cmake",
"nw.js",
"electron",
"boost",
"nan",
"napi",
"node-api",
"node-addon-api"
],
"main": "lib",
"version": "7.3.0",
"author": "Gábor Mező aka unbornchikken",
"maintainers": [
{
"name": "Julian Waller",
"email": "git@julusian.co.uk",
"url": "https://github.com/julusian/"
}
],
"repository": {
"type": "git",
"url": "git://github.com/cmake-js/cmake-js.git"
},
"bin": {
"cmake-js": "./bin/cmake-js"
},
"engines": {
"node": ">= 14.15.0"
},
"dependencies": {
"axios": "^1.6.5",
"debug": "^4",
"fs-extra": "^11.2.0",
"lodash.isplainobject": "^4.0.6",
"memory-stream": "^1.0.0",
"node-api-headers": "^1.1.0",
"npmlog": "^6.0.2",
"rc": "^1.2.7",
"semver": "^7.5.4",
"tar": "^6.2.0",
"url-join": "^4.0.1",
"which": "^2.0.2",
"yargs": "^17.7.2"
},
"devDependencies": {
"mocha": "*",
"nan": "^2.18.0",
"node-addon-api": "^6.1.0"
},
"scripts": {
"test": "mocha tests",
"lint": "eslint lib bin/cmake-js tests"
},
"files": [
"lib",
"bin",
"*.md",
"bindings.js",
"bindings.d.ts"
]
"name": "cmake-js",
"description": "CMake.js - a Node.js native addon build tool",
"license": "MIT",
"keywords": [
"native",
"addon",
"module",
"c",
"c++",
"bindings",
"build",
"buildtools",
"cmake",
"nw.js",
"electron",
"boost",
"nan",
"napi",
"node-api",
"node-addon-api"
],
"main": "lib",
"version": "7.3.1",
"author": "Gábor Mező aka unbornchikken",
"maintainers": [
{
"name": "Julian Waller",
"email": "git@julusian.co.uk",
"url": "https://github.com/julusian/"
}
],
"repository": {
"type": "git",
"url": "git://github.com/cmake-js/cmake-js.git"
},
"bin": {
"cmake-js": "./bin/cmake-js"
},
"engines": {
"node": ">= 14.15.0"
},
"dependencies": {
"axios": "^1.6.5",
"debug": "^4",
"fs-extra": "^11.2.0",
"memory-stream": "^1.0.0",
"node-api-headers": "^1.1.0",
"npmlog": "^6.0.2",
"rc": "^1.2.7",
"semver": "^7.5.4",
"tar": "^6.2.0",
"url-join": "^4.0.1",
"which": "^2.0.2",
"yargs": "^17.7.2"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"mocha": "*",
"nan": "^2.22.2",
"node-addon-api": "^6.1.0",
"prettier": "^3.2.2"
},
"scripts": {
"test": "mocha tests",
"lint": "eslint lib bin/cmake-js tests"
},
"files": [
"lib",
"bin",
"*.md",
"bindings.js",
"bindings.d.ts"
],
"packageManager": "yarn@1.22.22+sha256.c17d3797fb9a9115bf375e31bfd30058cac6bc9c3b8807a3d8cb2094794b51ca"
}
+45
-47

@@ -7,4 +7,5 @@ # CMake.js (MIT)

## About
CMake.js is a Node.js native addon build tool which works (almost) *exactly* like [node-gyp](https://github.com/TooTallNate/node-gyp), but instead of [gyp](http://en.wikipedia.org/wiki/GYP_%28software%29), it is based on [CMake](http://cmake.org) build system. It's compatible with the following runtimes:
CMake.js is a Node.js native addon build tool which works (almost) _exactly_ like [node-gyp](https://github.com/TooTallNate/node-gyp), but instead of [gyp](http://en.wikipedia.org/wiki/GYP_%28software%29), it is based on [CMake](http://cmake.org) build system. It's compatible with the following runtimes:
- Node.js 14.15+ since CMake.js v7.0.0 (for older runtimes please use an earlier version of CMake.js). Newer versions can produce builds targeting older runtimes

@@ -89,9 +90,9 @@ - [NW.js](https://github.com/nwjs/nw.js): all CMake.js based native modules are compatible with NW.js out-of-the-box, there is no [nw-gyp like magic](https://github.com/nwjs/nw.js/wiki/Using-Node-modules#3rd-party-modules-with-cc-addons) required

- A proper C/C++ compiler toolchain of the given platform
- **Windows**:
- [Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/). If you installed nodejs with the installer, you can install these when prompted.
- An alternate way is to install the [Chocolatey package manager](https://chocolatey.org/install), and run `choco install visualstudio2017-workload-vctools` in an Administrator Powershell
- If you have multiple versions installed, you can select a specific version with `npm config set msvs_version 2017` (Note: this will also affect `node-gyp`)
- **Unix/Posix**:
- Clang or GCC
- Ninja or Make (Ninja will be picked if both present)
- **Windows**:
- [Visual C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/). If you installed nodejs with the installer, you can install these when prompted.
- An alternate way is to install the [Chocolatey package manager](https://chocolatey.org/install), and run `choco install visualstudio2017-workload-vctools` in an Administrator Powershell
- If you have multiple versions installed, you can select a specific version with `npm config set msvs_version 2017` (Note: this will also affect `node-gyp`)
- **Unix/Posix**:
- Clang or GCC
- Ninja or Make (Ninja will be picked if both present)

@@ -104,3 +105,3 @@ ## Usage

In a nutshell. *(For more complete documentation please see [the first tutorial](https://github.com/unbornchikken/cmake-js/wiki/TUTORIAL-01-Creating-a-native-module-by-using-CMake.js-and-NAN).)*
In a nutshell. _(For more complete documentation please see [the first tutorial](https://github.com/unbornchikken/cmake-js/wiki/TUTORIAL-01-Creating-a-native-module-by-using-CMake.js-and-NAN).)_

@@ -111,12 +112,7 @@ - Install cmake-js for your module `npm install --save cmake-js`

```cmake
cmake_minimum_required(VERSION 3.15)
cmake_policy(SET CMP0091 NEW)
cmake_policy(SET CMP0042 NEW)
cmake_minimum_required(VERSION 3.15...3.31)
project(your-addon-name-here)
project (your-addon-name-here)
add_compile_definitions(-DNAPI_VERSION=4)
add_definitions(-DNAPI_VERSION=4)
include_directories(${CMAKE_JS_INC})
file(GLOB SOURCE_FILES "your-source files-location-here")

@@ -126,3 +122,5 @@

set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "" SUFFIX ".node")
target_link_libraries(${PROJECT_NAME} ${CMAKE_JS_LIB})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_JS_INC})
target_link_libraries(${PROJECT_NAME} PRIVATE ${CMAKE_JS_LIB})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_17)

@@ -236,2 +234,3 @@ if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)

In command prompt:
```

@@ -267,11 +266,11 @@ cmake-js compile --CDFOO="bar"

{
"name": "ta-taram-taram",
"description": "pa-param-pam-pam",
"version": "1.0.0",
"main": "app.js",
"cmake-js": {
"runtime": "node",
"runtimeVersion": "0.12.0",
"arch": "ia32"
}
"name": "ta-taram-taram",
"description": "pa-param-pam-pam",
"version": "1.0.0",
"main": "app.js",
"cmake-js": {
"runtime": "node",
"runtimeVersion": "0.12.0",
"arch": "ia32"
}
}

@@ -283,9 +282,8 @@ ```

- **runtime**: application's target runtime, possible values are:
- `node`: Node.js
- `nw`: nw.js
- `electron`: Electron
- `node`: Node.js
- `nw`: nw.js
- `electron`: Electron
- **runtimeVersion**: version of the application's target runtime, for example: `0.12.1`
- **arch**: architecture of application's target runtime (eg: `x64`, `ia32`, `arm64`, `arm`). *Notice: on non-Windows systems the C++ toolset's architecture's gonna be used despite this setting. If you don't specify this on Windows, then architecture of the main node runtime is gonna be used, so you have to choose a matching nw.js runtime.*
- **arch**: architecture of application's target runtime (eg: `x64`, `ia32`, `arm64`, `arm`). _Notice: on non-Windows systems the C++ toolset's architecture's gonna be used despite this setting. If you don't specify this on Windows, then architecture of the main node runtime is gonna be used, so you have to choose a matching nw.js runtime._
#### Node-API and `node-addon-api`

@@ -298,3 +296,3 @@

different versions of Node.js that support Node-API which includes
all versions of Node.js v10.x and later.
all versions of Node.js v10.x and later.

@@ -306,2 +304,3 @@ To compile a native module that uses only the

You must also add the following lines to your CMakeLists.txt, to allow for building on windows
```

@@ -352,7 +351,7 @@ if(MSVC AND CMAKE_JS_NODELIB_DEF AND CMAKE_JS_NODELIB_TARGET)

{
"cmake-js": {
"runtime": "nw",
"runtimeVersion": "nw.js-version-here",
"arch": "whatever-setting-is-appropriate-for-your-application's-windows-build"
}
"cmake-js": {
"runtime": "nw",
"runtimeVersion": "nw.js-version-here",
"arch": "whatever-setting-is-appropriate-for-your-application's-windows-build"
}
}

@@ -363,4 +362,4 @@ ```

#### Heroku
#### Heroku
[Heroku](https://heroku.com) uses the concept of a [buildpack](https://devcenter.heroku.com/articles/buildpacks) to define

@@ -376,9 +375,9 @@ how an application should be prepared to run in a [dyno](https://devcenter.heroku.com/articles/dynos).

- Set the applications' buildpack to
[https://github.com/heroku/heroku-buildpack-multi.git](https://github.com/heroku/heroku-buildpack-multi.git)
[https://github.com/heroku/heroku-buildpack-multi.git](https://github.com/heroku/heroku-buildpack-multi.git)
- In the root directory of the application,
create a file called `.buildpacks` with these two lines:
create a file called `.buildpacks` with these two lines:
https://github.com/brave/heroku-cmake-buildpack.git
https://github.com/heroku/heroku-buildpack-nodejs.git
https://github.com/brave/heroku-cmake-buildpack.git
https://github.com/heroku/heroku-buildpack-nodejs.git

@@ -390,3 +389,2 @@ - Deploy the application to have the changes take effect

## Tutorials

@@ -401,5 +399,5 @@

* [@julusian/jpeg-turbo](https://github.com/julusian/node-jpeg-turbo) - A Node-API wrapping around libjpeg-turbo. cmake-js was a good fit here, as libjpeg-turbo provides cmake files that can be used, and would be hard to replicate correctly in node-gyp
* [node-datachannel](https://github.com/murat-dogan/node-datachannel) - Easy to use WebRTC data channels and media transport
* [aws-iot-device-sdk-v2](https://github.com/aws/aws-iot-device-sdk-js-v2) AWS IoT Device SDK for JavaScript v2
- [@julusian/jpeg-turbo](https://github.com/julusian/node-jpeg-turbo) - A Node-API wrapping around libjpeg-turbo. cmake-js was a good fit here, as libjpeg-turbo provides cmake files that can be used, and would be hard to replicate correctly in node-gyp
- [node-datachannel](https://github.com/murat-dogan/node-datachannel) - Easy to use WebRTC data channels and media transport
- [aws-iot-device-sdk-v2](https://github.com/aws/aws-iot-device-sdk-js-v2) AWS IoT Device SDK for JavaScript v2

@@ -406,0 +404,0 @@ Open a PR to add your own project here.

Sorry, the diff of this file is not supported yet