diff --git a/scripts/configure.js b/scripts/configure.js index c742c680..c9c5b582 100644 --- a/scripts/configure.js +++ b/scripts/configure.js @@ -5,318 +5,163 @@ const fs = require('fs'); const path = require('path'); const child_process = require('child_process'); -const buildDir = process.cwd(); - -console.log('Build dir is: ' + buildDir); - -const osName = os.type(); - -var lldbVersion; // Similar to what `llvm-config --version` returns -var lldbInstallDir; // Where the lldb installation is, `llvm-config --prefix` - -// Need to determine: -// - What level of lldb we are running. -// - If we need the headers. (Linux may have them installed) -var lldbExe = 'lldb'; - -if (osName === 'Darwin') { - lldbVersion = getDarwinRelease(); - - if (lldbVersion === undefined) { - console.log('Unable to locate lldb binary. llnode installation failed.'); - process.exit(1); - } - - console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); - const installedDir = getDarwinInstallDir(); - if (installedDir === undefined) { - const lldbHeadersBranch = lldbVersionToBranch(lldbVersion); - lldbInstallDir = 'lldb-' + lldbVersion; - cloneHeaders(lldbHeadersBranch, lldbInstallDir, buildDir); - fs.writeFileSync('options.gypi', '{}', 'utf-8'); - } else { - lldbInstallDir = installedDir; - setDarwinBuildDir(); - } -} else if (osName === 'Linux') { - lldbExe = getLldbExecutable(); - lldbVersion = getLinuxVersion(lldbExe); - - if (lldbVersion === undefined) { - console.log('Unable to locate lldb binary. llnode installation failed.'); - process.exit(1); - } - - console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); - const installedDir = getLinuxInstallDir(lldbVersion); - if (installedDir === undefined) { - const lldbHeadersBranch = lldbVersionToBranch(lldbVersion); - lldbInstallDir = 'lldb-' + lldbVersion; - cloneHeaders(lldbHeadersBranch, lldbInstallDir, buildDir); - fs.writeFileSync('options.gypi', '{}', 'utf-8'); - } else { - lldbInstallDir = installedDir; - } -} else if (osName === 'FreeBSD') { - lldbExe = getLldbExecutable(); - lldbVersion = getFreeBSDVersion(lldbExe); - - if (lldbVersion === undefined) { - console.log('Unable to locate lldb binary. llnode installation failed.'); - process.exit(1); - } - - console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); - const installedDir = getFreeBSDInstallDir(lldbVersion); - if (installedDir === undefined) { - // As this is a BSD we know this system is in an improper state - // So we can exit with an error - console.log('The system isn\'t set up correcly.'); - console.log('Try `pkg install llvm39'); - console.log('And `ln -s /usr/local/bin/lldb39 /usr/bin/lldb`'); - process.exit(1); - } else { - lldbInstallDir = installedDir; - } +const lldb = require('./lldb'); + +function main() { + const buildDir = process.cwd(); + console.log('Build dir is: ' + buildDir); + const osName = os.type(); + const installation = configureInstallation(osName, buildDir); + linkHeadersDir(installation.prefix); + const gypDir = getGypDir(buildDir); + linkGyp(gypDir); + writeLlnodeScript(buildDir, installation.executable, osName); + // Exit with success. + process.exit(0); } -// This should be equivalent to `llvm-config --includedir`/lldb -function getLldbHeadersPath(lldbInstallDir) { - return path.join(lldbInstallDir, 'include', 'lldb'); -} - -// Check out source code of the LLDB for headers -// TODO: The llvm project is probably moving to github soon at that point we -// should stop using the mirror. -function cloneHeaders(lldbHeadersBranch, lldbInstallDir, buildDir) { - const lldbHeaders = getLldbHeadersPath(lldbInstallDir); - if (!fs.existsSync(lldbInstallDir)) { - console.log(`Cloning lldb from ${lldbHeadersBranch} to ${lldbInstallDir}`); - child_process.execFileSync('git', - ['clone', '--depth=1', '-b', lldbHeadersBranch, - 'https://github.com/llvm-mirror/lldb.git', lldbInstallDir], - { - cwd: buildDir, - stdio: 'inherit' // show progress - }); - } else { - console.log(`Skip cloning lldb headers because ${lldbHeaders} exists`); - } -} +main(); + +/** + * Get and configure the lldb installation. The returned prefix + * should be linked to ./lldb + * @param {string} osName Name of the OS + * @param {string} buildDir Path of the project directory + * @returns {{executable: string, version: string, prefix: string}} + */ +function configureInstallation(osName, buildDir) { + // Need to determine: + // - What level of lldb we are running. + // - If we need to download the headers. (Linux may have them installed) + let installation; + let prefix; // Similar to what `llvm-config --prefix` returns -// Link to the headers file so we can run gyp_llnode directly and don't need to -// setup parameters to pass it. -console.log(`Linking lldb to installation directory ${lldbInstallDir}`); -try { - fs.unlinkSync('lldb'); -} catch (error) { - // File does not exist, no need to handle. -} -fs.symlinkSync(lldbInstallDir, 'lldb'); - -// npm explore has a different root folder when using -g -// So we are tacking on the extra the additional subfolders -var gypSubDir = 'node-gyp'; -if (process.env.npm_config_global) { - gypSubDir = 'npm/node_modules/node-gyp'; -} - -// npm can be in a different location than the current -// location for global installs so we need find out where the npm is -var npmLocation = child_process.execFileSync('which', ['npm']); -var npmModules = path.join(npmLocation.toString(), '../../lib/node_modules/npm'); - -// Initialize GYP -// We can use the node-gyp that comes with npm. -// We can locate it with npm -g explore npm npm explore node-gyp pwd -// It might have been neater to make node-gyp one of our dependencies -// *but* they don't get installed until after the install step has run. -var gypDir = child_process.execFileSync('npm', - ['-g', 'explore', npmModules, 'npm', 'explore', gypSubDir, 'pwd'], - {cwd: buildDir}).toString().trim(); -child_process.execSync('rm -rf tools'); -fs.mkdirSync('tools'); -console.log(`Linking tools/gyp to ${gypDir}/gyp`); -fs.symlinkSync(`${gypDir}/gyp`, 'tools/gyp'); - -fs.writeFileSync(`${buildDir}/llnode.sh`, scriptText(lldbExe)); - -// Exit with success. -process.exit(0); - -function lldbVersionToBranch(version) { - return 'release_' + version.replace('.', ''); -} - -// On Mac the lldb version string doesn't match the original lldb versions. -function getDarwinRelease() { - var versionFromConfig; - try { - versionFromConfig = child_process.execFileSync('llvm-config', [ - '--version' - ]).toString().trim(); - } catch (err) { - // No llvm-config, try to get the version from xcodebuild - } - if (versionFromConfig !== undefined) { - return versionFromConfig.split('.').slice(0, 2).join('.'); - } - - var xcodeStr; - try { - xcodeStr = child_process.execFileSync('xcodebuild', [ - '-version' - ]).toString(); - } catch (err) { - return undefined; - } - var versionStr = ''; - var splitStr = xcodeStr.split(os.EOL); - for (var str of splitStr) { - if (str.includes('Xcode')) { - versionStr = str.split(' ')[1]; - break; + if (osName === 'Darwin') { + const darwin = require('./darwin'); + installation = darwin.getLldbInstallation(); + prefix = installation.prefix; + if (prefix === undefined) { // Using Xcode installation + prefix = lldb.cloneHeaders(installation.version, buildDir); + } else { // Using custom installation + // Need to configure with the custom prefix + const config = { + variables: { 'lldb_build_dir%': prefix } + }; + writeConfig(config); } - } - // console.log('Xcode version is ' + version_str) - - var version = parseFloat(versionStr); - if (version >= 8.3) { - return '3.9'; - } else if (version > 8.0) { - return '3.8'; + } else if (osName === 'Linux') { + const linux = require('./linux'); + installation = linux.getLldbInstallation(); + if (installation.prefix === undefined) + // Could not find the headers, need to download them + prefix = lldb.cloneHeaders(installation.version, buildDir); + else + prefix = installation.prefix; + + // ./lldb will always be linked to the prefix on Linux + writeConfig({}); + } else if (osName === 'FreeBSD') { + const freebsd = require('./freebsd'); + installation = freebsd.getLldbInstallation(); + prefix = installation.prefix; + // ./lldb will always be linked to the prefix + writeConfig({}); } else { - return '3.4'; + console.log(`Unsupported OS: ${osName}`); + process.exit(1); } -} -function setDarwinBuildDir() { - const prefix = child_process.execFileSync('llvm-config', [ - '--prefix' - ]).toString().trim(); - const options = JSON.stringify({ - variables: { 'lldb_build_dir%': prefix } - }, null, 2); - fs.writeFileSync('options.gypi', options, 'utf-8'); - console.log('Overwriting options.gypi with output from llvm-config:'); - console.log(options); + return { + executable: installation.executable, + version: installation.version, + prefix + }; } -function getDarwinInstallDir() { - var installedDir; +/** + * Link to the headers file so we can run gyp_llnode directly and don't need to + * setup parameters to pass. + * @param {string} lldbInstallDir The destination of the symlink + */ +function linkHeadersDir(lldbInstallDir) { + console.log(`Linking lldb to installation directory ${lldbInstallDir}`); try { - installedDir = child_process.execFileSync('llvm-config', [ - '--prefix' - ]).toString().trim(); - } catch (err) { - // Return undefined, we will download the headers. - } - if (installedDir !== undefined && - fs.existsSync(getLldbHeadersPath(installedDir))) { - return installedDir; + fs.unlinkSync('lldb'); + } catch (error) { + // File does not exist, no need to handle. } - return undefined; + fs.symlinkSync(lldbInstallDir, 'lldb'); } -// Find the 'best' lldb to use. Either: -// - the one specified by the user using npm --lldb_exe=... install llnode -// - the default lldb executable -// - the higest known lldb version -// - the names of future releases are predictable for linux -function getLldbExecutable() { - var lldbExe = process.env.npm_config_lldb_exe; - if (lldbExe === undefined) { - var lldbExeNames = [ - 'lldb', 'lldb-5.0', 'lldb-4.0', - 'lldb-3.9', 'lldb-3.8', 'lldb-3.7', 'lldb-3.6' - ]; - for (var lldbExeVersion of lldbExeNames) { - try { - lldbExe = child_process.execSync('which ' + - lldbExeVersion).toString().trim(); - // If the result starts with '/' `which` found a path. - if (lldbExe.startsWith('/')) { - break; - } - } catch (err) { - // Do nothing - we expect not to find some of these. - } - } - } - return lldbExe; +/** + * Get the path to the GYP installation + * @param {string} buildDir Path of the project directory + */ +function getGypDir(buildDir) { + // npm explore has a different root folder when using -g + // So we are tacking on the extra the additional subfolders + let gypSubDir = 'node-gyp'; + if (process.env.npm_config_global) + gypSubDir = 'npm/node_modules/node-gyp'; + + // npm can be in a different location than the current + // location for global installs so we need find out where the npm is + let npmLocation = child_process.execFileSync('which', ['npm']); + let npmModules = path.join( + npmLocation.toString(), '../../lib/node_modules/npm'); + + // Initialize GYP + // We can use the node-gyp that comes with npm. + // We can locate it with npm -g explore npm npm explore node-gyp pwd + // It might have been neater to make node-gyp one of our dependencies + // *but* they don't get installed until after the install step has run. + let gypDir = child_process.execFileSync( + 'npm', + ['-g', 'explore', npmModules, 'npm', 'explore', gypSubDir, 'pwd'], + { cwd: buildDir } + ).toString().trim(); + return gypDir; } -// There are multiple versions of lldb available for the various linux distos. -// Use the default unless --llnode_exe= has been set on the command line. -function getLinuxVersion(lldbExe) { - var lldbStr; - try { - lldbStr = child_process.execFileSync(lldbExe, ['-v']).toString(); - } catch (err) { - return undefined; - } - // Ignore minor revisions like 3.8.1 - let versionMatch = lldbStr.match(/version (\d.\d)/); - if (versionMatch) { - return versionMatch[1]; - } - return undefined; +/** + * Link tools/gyp to the GYP installation + * @param {string} gypDir path to the GYP installation + */ +function linkGyp(gypDir) { + child_process.execSync('rm -rf tools'); + fs.mkdirSync('tools'); + console.log(`Linking tools/gyp to ${gypDir}/gyp`); + fs.symlinkSync(`${gypDir}/gyp`, 'tools/gyp'); } -// Shim this for consistancy in OS naming -function getFreeBSDVersion(lldbExe) { - // Strip the dots for BSD - return getLinuxVersion(lldbExe).replace('.', ''); +/** + * Generate the llnode shortcut script + * @param {string} buildDir Path of the project directory + * @param {string} lldbExe Name of the lldb executable + * @param {string} osName Name of the OS + */ +function writeLlnodeScript(buildDir, lldbExe, osName) { + const text = scriptText(osName, lldbExe); + const scriptPath = path.join(buildDir, 'llnode.sh'); + console.log(`Writing llnode.sh shortcut to ${scriptPath}`); + fs.writeFileSync(scriptPath, text); } -function getFreeBSDInstallDir(version) { - console.log('Checking for headers, version is ' + version); - - try { - var installDir = child_process.execFileSync('llvm-config' + version, - ['--prefix']).toString().trim(); - if (fs.existsSync(installDir + '/include/lldb')) { - return installDir; - } - } catch (err) { - console.log(installDir + '/include/lldb doesn\'nt exist'); - console.log('Please see README.md'); - console.log(err); - process.exit(1); - } - return undefined; -} - -function getLinuxInstallDir(version) { - // Get the directory which should contain the headers and - // check if they are present. - // (Using the installed headers will ensure we have the correct ones.) - console.log('Checking for headers, version is ' + version); - try { - var installDir = child_process.execFileSync('llvm-config-' + version, - ['--prefix']).toString().trim(); - // console.log('Checking for directory ' + include_dir); - // Include directory doesn't need include/lldb on the end but the llvm - // headers can be installed without the lldb headers so check for them. - if (fs.existsSync(installDir + '/include/lldb')) { - // console.log('Found ' + include_dir); - return installDir; - } - } catch (err) { - // Return undefined, we will download the headers. - } - // On Redhat the headers are just installed in /usr/include - if (fs.existsSync('/usr/include/lldb')) { - return '/usr'; - } - return undefined; +/** + * Write configuration to options.gypi + * @param {string} config + */ +function writeConfig(config) { + const options = JSON.stringify(config, null, 2); + fs.writeFileSync('options.gypi', options, 'utf-8'); + console.log('Writing options.gypi:'); + console.log(options); } -function scriptText(lldbExe) { +function scriptText(osName, lldbExe) { let lib = 'llnode.so'; - if (osName === 'Darwin') { + if (osName === 'Darwin') lib = 'llnode.dylib'; - } return `#!/bin/sh @@ -326,9 +171,12 @@ SCRIPT_PATH=\`dirname $LLNODE_SCRIPT\` if [ \`basename $SCRIPT_PATH\` = ".bin" ]; then # llnode installed locally in node_modules/.bin LLNODE_PLUGIN="$SCRIPT_PATH/../llnode/${lib}" -else +elif [ -e $SCRIPT_PATH/../lib/node_modules/llnode/${lib} ]; then # llnode installed globally in lib/node_modules LLNODE_PLUGIN="$SCRIPT_PATH/../lib/node_modules/llnode/${lib}" +else + # The scrips is invoked directly + LLNODE_PLUGIN="$SCRIPT_PATH/${lib}" fi ${lldbExe} --one-line "plugin load $LLNODE_PLUGIN" --one-line "settings set prompt '(llnode) '" $@ diff --git a/scripts/darwin.js b/scripts/darwin.js new file mode 100644 index 00000000..ae37e578 --- /dev/null +++ b/scripts/darwin.js @@ -0,0 +1,127 @@ + +'use strict'; + +const child_process = require('child_process'); +const os = require('os'); +const fs = require('fs'); +const lldb = require('./lldb'); + +/** + * On Mac the lldb version string doesn't match the original lldb versions, + * we need to get it either from `llvm-config --version` (custom installation) + * or `xcodebuild -version` (Xcode installation). + * + * @returns {string|undefined} Deduced version of lldb, undefined if failed + */ +function getLldbVersion() { + let versionFromConfig; + try { + versionFromConfig = child_process.execFileSync('llvm-config', [ + '--version' + ]).toString().trim(); + } catch (err) { + // No llvm-config, try to get the version from xcodebuild + } + if (versionFromConfig !== undefined) { + const result = versionFromConfig.split('.').slice(0, 2).join('.'); + console.log(`Retrieved lldb version ${result} ` + + 'from `llvm-config --version`'); + return result; + } + + let xcodeStr; + try { + xcodeStr = child_process.execFileSync( + 'xcodebuild', ['-version'] + ).toString().trim(); + } catch (err) { + console.log(err); + console.log('Could not retrieve Xcode version from `xcodebuild -version`'); + return undefined; + } + + let xcodeVersion; + let splitStr = xcodeStr.split(os.EOL); + for (let str of splitStr) + if (str.includes('Xcode')) { + xcodeVersion = str.split(' ')[1]; + break; + } + + if (xcodeVersion === undefined) { + console.log(`Could not get Xcode version from:\n${xcodeStr}`); + return undefined; + } + + let result; + let version = parseFloat(xcodeVersion); + if (version >= 8.3) + result = '3.9'; + else if (version > 8.0) + result = '3.8'; + else + result = '3.4'; + + if (result !== undefined) + console.log('Deduced lldb version from Xcode version: ' + + `Xcode ${xcodeVersion} -> lldb ${result}`); + else + console.log('Could not deduce lldb version from Xcode version' + + xcodeVersion); + + return result; +} + +/** + * Get the directory to the lldb installation, if it returns undefined, + * we need to download the headers to ./lldb/include/lldb + * @returns {string|undefined} lldb installation prefix, undefined if failed + */ +function getInstallDir() { + var installedDir; + try { + installedDir = child_process.execFileSync('llvm-config', [ + '--prefix' + ]).toString().trim(); + } catch (err) { + // Return undefined, we will download the headers. + } + if (installedDir !== undefined && + fs.existsSync(lldb.getHeadersPath(installedDir))) + return installedDir; + + return undefined; +} + +/** + * Get the lldb installation. If prefix is undefined, the headers need to + * be downloaded. + * The version string will be in the form like '3.9' + * @returns {{executable: string, version: string, ?prefix: string}} + */ +function getLldbInstallation() { + const lldbExe = process.env.npm_config_lldb_exe || 'lldb'; + // We cannot just use the executable specified with + // process.env.npm_config_lldb_exe to determine the version of lldb + // because we do not know how. We can only use llvm-config or xcodebuild + // to retrieve the version. + const lldbVersion = getLldbVersion(); + + if (lldbVersion === undefined) { + console.log('Unable to deduce the version of lldb, ' + + 'llnode installation failed.'); + process.exit(1); + } + + console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); + const installedDir = getInstallDir(); + return { + executable: lldbExe, + version: lldbVersion, + prefix: installedDir + }; +} + +module.exports = { + getLldbInstallation +}; diff --git a/scripts/freebsd.js b/scripts/freebsd.js new file mode 100644 index 00000000..a05d14ab --- /dev/null +++ b/scripts/freebsd.js @@ -0,0 +1,89 @@ +'use strict'; + +const child_process = require('child_process'); +const fs = require('fs'); + +const linux = require('./linux'); +const lldb = require('./lldb'); + +/** + * Get the version of the lldb executable, + * shim this for consistancy in OS naming + * @param {string} lldbExe + * @returns {string} lldb version in the form like '39' + */ +function getLldbVersion(lldbExe) { + // Strip the dots for BSD + return linux.getLldbVersion(lldbExe).replace('.', ''); +} + +function printAdvice(version) { + console.log('The system isn\'t set up correcly.'); + console.log(`Try \`pkg install llvm${version}\``); + console.log(`And \`ln -s /usr/local/bin/lldb${version} /usr/bin/lldb\``); +} + +/** + * Get the installation directory (prefix) of lldb + * @param {string} version lldb version for FreeBSD, e.g. '39' for 'lldb-3.9' + * @returns {string} Directory of the lldb installation + */ +function getInstallDir(version) { + // Get the directory which should contain the headers and + // check if they are present. + // (Using the installed headers will ensure we have the correct ones.) + console.log('Checking for headers, version is ' + version); + let installDir; + try { + // Notice the executable is named differently from Linux + installDir = child_process.execFileSync( + `llvm-config${version}`, + ['--prefix'] + ).toString().trim(); + } catch (err) { + // As this is a BSD we know this system is in an improper state + // So we can exit with an error + console.log(`Could not execute llvm-config${version}`); + printAdvice(version); + console.log(err); + process.exit(1); + } + + const headers = lldb.getHeadersPath(installDir); + if (!fs.existsSync(headers)) { + // As this is a BSD we know this system is in an improper state + // So we can exit with an error + console.log(`Could not find ${headers}`); + printAdvice(version); + process.exit(1); + } + + return installDir; +} + +/** + * Get the lldb installation + * @returns {{executable: string, version: string, prefix: string}} + */ +function getLldbInstallation() { + const lldbExe = linux.getLldbExecutable(); + const lldbVersion = getLldbVersion(lldbExe); + + if (lldbVersion === undefined) { + console.log('Unable to get lldb binary or its version. ' + + 'llnode installation failed.'); + process.exit(1); + } + + console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); + const installedDir = getInstallDir(lldbVersion); + return { + executable: lldbExe, + version: lldbVersion, + prefix: installedDir + }; +} + +module.exports = { + getLldbInstallation +}; diff --git a/scripts/linux.js b/scripts/linux.js new file mode 100644 index 00000000..8d07f629 --- /dev/null +++ b/scripts/linux.js @@ -0,0 +1,136 @@ + +'use strict'; + +const child_process = require('child_process'); +const fs = require('fs'); +const lldb = require('./lldb'); + +/** + * Find the 'best' lldb to use, exit the process with 1 if failed. + * The search happens in the following order: + * - the one specified by the user using npm --lldb_exe=... install llnode + * - the default lldb executable (`lldb`) + * - the higest known lldb version (`lldb-x.y`) + * - the names of future releases are predictable for linux + * + * @returns {string} Name of the lldb executable + */ +function getLldbExecutable() { + var lldbExe = process.env.npm_config_lldb_exe; + if (lldbExe !== undefined) + return lldbExe; + + var lldbExeNames = [ + 'lldb', 'lldb-5.0', 'lldb-4.0', + 'lldb-3.9', 'lldb-3.8', 'lldb-3.7', 'lldb-3.6' + ]; + + for (var lldbExeVersion of lldbExeNames) + try { + lldbExe = child_process.execSync('which ' + + lldbExeVersion).toString().trim(); + // If the result starts with '/' `which` found a path. + if (lldbExe.startsWith('/')) + break; + } catch (err) { + // Do nothing - we expect not to find some of these. + } + + if (!lldbExe) { + console.log('Could not find any usable lldb binary'); + console.log('Please see the README.md on how to install lldb'); + process.exit(1); + } + return lldbExe; +} + +/** + * Get the lldb version from the lldb executable, exit the process with 1 + * if failed. + * @param {string} lldbExe + * @returns {string} Version of the executable in the form like '3.9' + */ +function getLldbVersion(lldbExe) { + var lldbStr; + try { + lldbStr = child_process.execFileSync(lldbExe, ['-v']).toString(); + } catch (err) { + console.log(err); + console.log(`Unable to get the version from the lldb binary ${lldbExe}`); + process.exit(1); + } + // Ignore minor revisions like 3.8.1 + const versionMatch = lldbStr.match(/version (\d.\d)/); + if (versionMatch) + return versionMatch[1]; + + console.log(`Unable to get the version from the lldb binary ${lldbExe}`); + console.log(`Output from \`${lldbExe} -v\` was ${lldbStr}`); + process.exit(1); +} + +/** + * Get the directory to the lldb installation, if it returns undefined, + * we need to download the headers to ./lldb/include/lldb + * @param {string} version Version of the lldb executable + * @returns {string|undefined} lldb installation prefix, undefined if failed + */ +function getInstallDir(version) { + // Get the directory which should contain the headers and + // check if they are present. + // (Using the installed headers will ensure we have the correct ones.) + console.log('Checking for headers, version is ' + version); + + let installDir; + try { + installDir = child_process.execFileSync( + `llvm-config-${version}`, + ['--prefix'] + ).toString().trim(); + } catch (err) { + // Could not get the headers through llvm-config, try another way + } + + if (!installDir) + // On Redhat the headers are just installed in /usr/include + if (fs.existsSync('/usr/include/lldb')) { + return '/usr'; + } else { + // We will download the headers + return undefined; + } + + // Include directory doesn't need include/lldb on the end but the llvm + // headers can be installed without the lldb headers so check for them. + const headers = lldb.getHeadersPath(installDir); + if (fs.existsSync(headers)) + return installDir; + + // We will download the headers + return undefined; +} + +/** + * Get the lldb installation. If prefix is undefined, the headers need to + * be downloaded. + * The version string will be in the form like '3.9' + * @returns {{executable: string, version: string, ?prefix: string}} + */ +function getLldbInstallation() { + const lldbExe = getLldbExecutable(); + const lldbVersion = getLldbVersion(lldbExe); + + console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); + const installedDir = getInstallDir(lldbVersion); + return { + executable: lldbExe, + version: lldbVersion, + prefix: installedDir + }; +} + +module.exports = { + getLldbExecutable, + getLldbVersion, + getLldbInstallation +}; diff --git a/scripts/lldb.js b/scripts/lldb.js new file mode 100644 index 00000000..32d9eb3c --- /dev/null +++ b/scripts/lldb.js @@ -0,0 +1,55 @@ +'use strcit'; + +const child_process = require('child_process'); +const path = require('path'); +const fs = require('fs'); + +/** + * @param {string} version lldb version, either in the form '3.9' or '39' + * @returns {string} Branch of the corresponding lldb release + */ +function versionToBranch(version) { + return 'release_' + version.replace('.', ''); +} + +/** + * Equivalent to `llvm-config --includedir`/lldb + * @param {string} lldbInstallDir Path to the lldb installation + * @returns {string} Path to the lldb headers + */ +function getHeadersPath(lldbInstallDir) { + return path.join(lldbInstallDir, 'include', 'lldb'); +} + +/** + * Check out source code of the lldb for headers + * TODO: The llvm project is probably moving to github soon at that point we + * should stop using the mirror. + * @param {string} lldbVersion Version of lldb, either like 3.9 or 39 + * @param {string} buildDir + * @returns {string} The directory where the source code is checked out + */ +function cloneHeaders(lldbVersion, buildDir) { + const lldbHeadersBranch = versionToBranch(lldbVersion); + const lldbInstallDir = `lldb-${lldbVersion}`; + + if (!fs.existsSync(path.join(buildDir, lldbInstallDir))) { + console.log(`Cloning lldb ${lldbHeadersBranch} into ${lldbInstallDir}`); + child_process.execFileSync('git', + ['clone', '--depth=1', '-b', lldbHeadersBranch, + 'https://github.com/llvm-mirror/lldb.git', lldbInstallDir], + { + cwd: buildDir, + stdio: 'inherit' // show progress + }); + } else { + console.log(`Skip cloning lldb headers because ${lldbInstallDir} exists`); + } + return lldbInstallDir; +} + +module.exports = { + versionToBranch, + getHeadersPath, + cloneHeaders +};