diff --git a/gyp_llnode b/gyp_llnode index 38f67290..d1891cdf 100755 --- a/gyp_llnode +++ b/gyp_llnode @@ -56,14 +56,14 @@ if __name__ == '__main__': # On msvs it will crash if it gets an absolute path. # On Mac/make it will crash if it doesn't get an absolute path. if sys.platform == 'win32': - args.append(os.path.join(root, 'llnode.gyp')) + args.append(os.path.join(root, 'llnode.gyp.json')) common_fn = os.path.join(root, 'common.gypi') options_fn = os.path.join(root, 'options.gypi') # we force vs 2010 over 2008 which would otherwise be the default for gyp if not os.environ.get('GYP_MSVS_VERSION'): os.environ['GYP_MSVS_VERSION'] = '2010' else: - args.append(os.path.join(os.path.abspath(root), 'llnode.gyp')) + args.append(os.path.join(os.path.abspath(root), 'llnode.gyp.json')) common_fn = os.path.join(os.path.abspath(root), 'common.gypi') options_fn = os.path.join(os.path.abspath(root), 'options.gypi') diff --git a/llnode.gyp b/llnode.gyp deleted file mode 100644 index ce6bd42d..00000000 --- a/llnode.gyp +++ /dev/null @@ -1,54 +0,0 @@ -{ - "variables": { - # gyp does not appear to let you test for undefined variables, so define - # lldb_build_dir as empty so we can test it later. - "lldb_build_dir%": "" - }, - - "targets": [{ - "target_name": "llnode", - "type": "shared_library", - "product_prefix": "", - - "include_dirs": [ - ".", - "<(lldb_dir)/include", - ], - - "sources": [ - "src/llnode.cc", - "src/llv8.cc", - "src/llv8-constants.cc", - "src/llscan.cc", - ], - - "conditions": [ - [ "OS == 'mac'", { - "conditions": [ - [ "lldb_build_dir == ''", { - "variables": { - "mac_shared_frameworks": "/Applications/Xcode.app/Contents/SharedFrameworks", - }, - "xcode_settings": { - "OTHER_LDFLAGS": [ - "-F<(mac_shared_frameworks)", - "-Wl,-rpath,<(mac_shared_frameworks)", - "-framework LLDB", - ], - }, - }, - # lldb_builddir != "" - { - "xcode_settings": { - "OTHER_LDFLAGS": [ - "-Wl,-rpath,<(lldb_build_dir)/lib", - "-L<(lldb_build_dir)/lib", - "-l<(lldb_lib)", - ], - }, - }], - ], - }], - ] - }], -} diff --git a/llnode.gyp b/llnode.gyp new file mode 120000 index 00000000..8061de5a --- /dev/null +++ b/llnode.gyp @@ -0,0 +1 @@ +llnode.gyp.json \ No newline at end of file diff --git a/llnode.gyp.json b/llnode.gyp.json new file mode 100644 index 00000000..ce6bd42d --- /dev/null +++ b/llnode.gyp.json @@ -0,0 +1,54 @@ +{ + "variables": { + # gyp does not appear to let you test for undefined variables, so define + # lldb_build_dir as empty so we can test it later. + "lldb_build_dir%": "" + }, + + "targets": [{ + "target_name": "llnode", + "type": "shared_library", + "product_prefix": "", + + "include_dirs": [ + ".", + "<(lldb_dir)/include", + ], + + "sources": [ + "src/llnode.cc", + "src/llv8.cc", + "src/llv8-constants.cc", + "src/llscan.cc", + ], + + "conditions": [ + [ "OS == 'mac'", { + "conditions": [ + [ "lldb_build_dir == ''", { + "variables": { + "mac_shared_frameworks": "/Applications/Xcode.app/Contents/SharedFrameworks", + }, + "xcode_settings": { + "OTHER_LDFLAGS": [ + "-F<(mac_shared_frameworks)", + "-Wl,-rpath,<(mac_shared_frameworks)", + "-framework LLDB", + ], + }, + }, + # lldb_builddir != "" + { + "xcode_settings": { + "OTHER_LDFLAGS": [ + "-Wl,-rpath,<(lldb_build_dir)/lib", + "-L<(lldb_build_dir)/lib", + "-l<(lldb_lib)", + ], + }, + }], + ], + }], + ] + }], +} diff --git a/package.json b/package.json index ff941ecb..e4f00bf5 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,31 @@ { "name": "llnode", - "version": "1.4.0", + "version": "1.4.1", "description": "llnode test suite", "main": "no-entry-sorry.js", "directories": { "test": "test" }, + "//": "We need to use the install scripts as llnode must be built on the machine it's deployed on.", + "//": "(Blame C++)", "scripts": { + "preinstall" : "node scripts/configure.js", + "install" : "./gyp_llnode && make -C out/", + "postinstall" : "node scripts/cleanup.js", "test": "tape test/*-test.js" }, "repository": { "type": "git", - "url": "git+ssh://git@github.com/indutny/llnode.git" + "url": "git+ssh://git@github.com/nodejs/llnode.git" }, + "files" : [ + "llnode.gyp.json", + "gyp_llnode", + "common.gypi", + "src/", + "scripts/", + "out/" + ], "keywords": [ "llnode", "post", @@ -22,9 +35,9 @@ "license": "MIT", "gypfile": true, "bugs": { - "url": "https://github.com/indutny/llnode/issues" + "url": "https://github.com/nodejs/llnode/issues" }, - "homepage": "https://github.com/indutny/llnode#readme", + "homepage": "https://github.com/nodejs/llnode#readme", "devDependencies": { "tape": "^4.4.0" } diff --git a/scripts/cleanup.js b/scripts/cleanup.js new file mode 100644 index 00000000..9eec4796 --- /dev/null +++ b/scripts/cleanup.js @@ -0,0 +1,21 @@ +'use strict'; + +const os = require('os'); +const child_process = require('child_process'); + +const cwd = process.cwd(); +const osName = os.type(); +var libExt = 'so'; + +if (osName === 'Darwin') { + libExt = 'dylib'; +} + +const llnodeLib = `llnode.${libExt}`; + +// Move the library somewhere easy to remember. +console.log(`Copying ${cwd}/out/Release/${llnodeLib} to ${cwd}/${llnodeLib}`); +child_process.execSync(`mv ${cwd}/out/Release/${llnodeLib} ${cwd}/${llnodeLib}`); + +console.log(`${os.EOL}llnode plugin installed, load in lldb with:`); +console.log(`(lldb) plugin load ${cwd}/${llnodeLib}${os.EOL}`); diff --git a/scripts/configure.js b/scripts/configure.js new file mode 100644 index 00000000..abd312fa --- /dev/null +++ b/scripts/configure.js @@ -0,0 +1,201 @@ +'use strict'; + +const os = require('os'); +const fs = require('fs'); +const child_process = require('child_process'); + +const lldbReleases = { + '4.0': 'master', + '3.9': 'release_39', + '3.8': 'release_38', + '3.7': 'release_37', + '3.6': 'release_36', + '3.5': 'release_35', + '3.4': 'release_34', +}; + +const buildDir = process.cwd(); + +console.log('Build dir is: ' + buildDir); + +const osName = os.type(); + +var lldbVersion; +var lldbHeadersBranch; +var lldbIncludeDir; + +// 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); + } + + lldbHeadersBranch = lldbReleases[lldbVersion]; + lldbIncludeDir = 'lldb-' + lldbVersion; + +} 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('lldb_version is ' + lldb_version) + var installedHeadersDir = getLinuxHeadersDir(lldbVersion); + // console.log('installed_headers_dir is ' + installed_headers_dir); + if (installedHeadersDir === undefined) { + // Initialising lldb_headers_branch will cause us to clone them. + lldbHeadersBranch = lldbReleases[lldbVersion]; + lldbIncludeDir = 'lldb-' + lldbVersion; + } else { + lldbIncludeDir = installedHeadersDir; + } +} + +console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`); + +// Check out source code of the LLDB that is compatible with OS X's default lldb +// TODO: The llvm project is probably moving to github soon at that point we +// should stop using the mirror. +if (lldbHeadersBranch != undefined) { + console.log('Cloning lldb from ' + lldbHeadersBranch); + child_process.execFileSync('git', + ['clone', '--depth=1', '-b', lldbHeadersBranch, + 'https://github.com/llvm-mirror/lldb.git', lldbIncludeDir], + {cwd: buildDir}); +} + +// 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 include directory ${lldbIncludeDir}`); +fs.symlinkSync(lldbIncludeDir, 'lldb'); + +// 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', 'npm', 'npm', 'explore', 'node-gyp', 'pwd'], + {cwd: buildDir}).toString().trim(); +fs.mkdirSync('tools'); +console.log(`Linking tools/gyp to ${gypDir}/gyp`); +fs.symlinkSync(`${gypDir}/gyp`, 'tools/gyp'); + +// Exit with success. +process.exit(0); + +// On Mac the lldb version string doesn't match the original lldb versions. +function getDarwinRelease() { + 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.indexOf('Xcode') != -1) { + versionStr = str.split(' ')[1]; + break; + } + } + // console.log('Xcode version is ' + version_str) + + var version = parseFloat(versionStr); + if (version > 8.0) { + return '3.8'; + } else { + return '3.4'; + } +} + +// Find the 'best' lldb to use. Either: +// - the one specified by the user using npm --llnode_exe=... install llnode +// - the default lldb executable +// - the higest known lldb version +function getLldbExecutable() { + var lldbExe = process.env.npm_config_lldb_exe; + if (lldbExe === undefined) { + var lldbExeNames = ['lldb', '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; +} + +// 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 + if (lldbStr.indexOf('version 4.0') > 0) { + return '4.0'; + } else if (lldbStr.indexOf('version 3.9') > 0) { + return '3.9'; + } else if (lldbStr.indexOf('version 3.8') > 0) { + return '3.8'; + } else if (lldbStr.indexOf('version 3.7') > 0) { + return '3.7'; + } if (lldbStr.indexOf('version 3.6') > 0) { + return '3.6'; + } if (lldbStr.indexOf('version 3.5') > 0) { + return '3.5'; + } + return undefined; +} + +function getLinuxHeadersDir(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 includeDir = 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(includeDir + '/include/lldb')) { + // console.log('Found ' + include_dir); + return includeDir; + } + } 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; +}