UNPKG

cmake-js

Version:

CMake.js - a Node.js native addon build tool

227 lines (205 loc) 8.31 kB
"use strict"; const TargetOptions = require("./targetOptions"); const environment = require("./environment"); const assert = require("assert"); const CMLog = require("./cmLog"); const util = require('util') const { findVisualStudio } = environment.isWin ? require('./import/find-visualstudio') : {} 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; } Toolset.prototype.initialize = async function (install) { if (!this._initialized) { if (environment.isWin) { await this.initializeWin(install); } else { this.initializePosix(install); } this._initialized = true; } }; 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++'."); } } 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"; } } // 3: Flags if (environment.isOSX) { if (install) { this.log.verbose("TOOL", "Setting default OSX compiler flags."); } 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."); } }; 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; const isAboveVS16 = foundVsInfo.versionMajor >= 16; // 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."); } } this.linkerFlags.push("/DELAYLOAD:NODE.EXE"); if (this.targetOptions.isX86) { if (install) { this.log.verbose("TOOL", "Setting SAFESEH:NO linker flag."); } this.linkerFlags.push("/SAFESEH:NO"); } }; Toolset.prototype._getTopSupportedVisualStudioGenerator = async function () { const CMake = require("./cMake"); assert(environment.isWin); const selectedVs = await findVisualStudio(environment.runtimeVersion, this.options.msvsVersion) if (!selectedVs) return null; 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; } // 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;