Skip to content

Commit 2325ae3

Browse files
authored
package.json: Make llnode installable via npm (#60)
This updates package.json and adds scripts to allow llnode to be built via "npm install llnode" It doesn't create a Node.js module you can use via require('llnode'). (This may change in the future depending on project direction.) The npm name llnode has been reserved here: https://www.npmjs.com/package/llnode On Linux if lldb doesn't exist the scipts try lldb-3.9,3.8,3.7 executables instead. - Install scripts guess can be overridden with --lldb_exe option e.g. npm install --lldb_exe=`which lldb-3.9` PR-URL: #60 Reviewed-By: Fedor Indutny <fedor@indutny.com>
1 parent 4cda69c commit 2325ae3

File tree

6 files changed

+295
-59
lines changed

6 files changed

+295
-59
lines changed

gyp_llnode

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ if __name__ == '__main__':
5656
# On msvs it will crash if it gets an absolute path.
5757
# On Mac/make it will crash if it doesn't get an absolute path.
5858
if sys.platform == 'win32':
59-
args.append(os.path.join(root, 'llnode.gyp'))
59+
args.append(os.path.join(root, 'llnode.gyp.json'))
6060
common_fn = os.path.join(root, 'common.gypi')
6161
options_fn = os.path.join(root, 'options.gypi')
6262
# we force vs 2010 over 2008 which would otherwise be the default for gyp
6363
if not os.environ.get('GYP_MSVS_VERSION'):
6464
os.environ['GYP_MSVS_VERSION'] = '2010'
6565
else:
66-
args.append(os.path.join(os.path.abspath(root), 'llnode.gyp'))
66+
args.append(os.path.join(os.path.abspath(root), 'llnode.gyp.json'))
6767
common_fn = os.path.join(os.path.abspath(root), 'common.gypi')
6868
options_fn = os.path.join(os.path.abspath(root), 'options.gypi')
6969

llnode.gyp

Lines changed: 0 additions & 54 deletions
This file was deleted.

llnode.gyp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
llnode.gyp.json

llnode.gyp.json

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
{
2+
"variables": {
3+
# gyp does not appear to let you test for undefined variables, so define
4+
# lldb_build_dir as empty so we can test it later.
5+
"lldb_build_dir%": ""
6+
},
7+
8+
"targets": [{
9+
"target_name": "llnode",
10+
"type": "shared_library",
11+
"product_prefix": "",
12+
13+
"include_dirs": [
14+
".",
15+
"<(lldb_dir)/include",
16+
],
17+
18+
"sources": [
19+
"src/llnode.cc",
20+
"src/llv8.cc",
21+
"src/llv8-constants.cc",
22+
"src/llscan.cc",
23+
],
24+
25+
"conditions": [
26+
[ "OS == 'mac'", {
27+
"conditions": [
28+
[ "lldb_build_dir == ''", {
29+
"variables": {
30+
"mac_shared_frameworks": "/Applications/Xcode.app/Contents/SharedFrameworks",
31+
},
32+
"xcode_settings": {
33+
"OTHER_LDFLAGS": [
34+
"-F<(mac_shared_frameworks)",
35+
"-Wl,-rpath,<(mac_shared_frameworks)",
36+
"-framework LLDB",
37+
],
38+
},
39+
},
40+
# lldb_builddir != ""
41+
{
42+
"xcode_settings": {
43+
"OTHER_LDFLAGS": [
44+
"-Wl,-rpath,<(lldb_build_dir)/lib",
45+
"-L<(lldb_build_dir)/lib",
46+
"-l<(lldb_lib)",
47+
],
48+
},
49+
}],
50+
],
51+
}],
52+
]
53+
}],
54+
}

package.json

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,26 @@
66
"directories": {
77
"test": "test"
88
},
9+
"//": "We need to use the install scripts as llnode must be built on the machine it's deployed on.",
10+
"//": "(Blame C++)",
911
"scripts": {
12+
"preinstall" : "node scripts/configure.js",
13+
"install" : "./gyp_llnode && make -C out/",
14+
"postinstall" : "node scripts/cleanup.js",
1015
"test": "tape test/*-test.js"
1116
},
1217
"repository": {
1318
"type": "git",
14-
"url": "git+ssh://git@github.com/indutny/llnode.git"
19+
"url": "git+ssh://git@github.com/nodejs/llnode.git"
1520
},
21+
"files" : [
22+
"llnode.gyp.json",
23+
"gyp_llnode",
24+
"common.gypi",
25+
"src/",
26+
"scripts/",
27+
"out/"
28+
],
1629
"keywords": [
1730
"llnode",
1831
"post",
@@ -22,9 +35,9 @@
2235
"license": "MIT",
2336
"gypfile": true,
2437
"bugs": {
25-
"url": "https://github.com/indutny/llnode/issues"
38+
"url": "https://github.com/nodejs/llnode/issues"
2639
},
27-
"homepage": "https://github.com/indutny/llnode#readme",
40+
"homepage": "https://github.com/nodejs/llnode#readme",
2841
"devDependencies": {
2942
"tape": "^4.4.0"
3043
}

scripts/cleanup.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
'use strict';
2+
3+
const os = require('os');
4+
const child_process = require('child_process');
5+
6+
const cwd = process.cwd();
7+
const osName = os.type();
8+
var libExt = 'so';
9+
10+
if (osName === 'Darwin') {
11+
libExt = 'dylib';
12+
}
13+
14+
const llnodeLib = `llnode.${libExt}`;
15+
16+
// Move the library somewhere easy to remember.
17+
console.log(`Copying ${cwd}/out/Release/${llnodeLib} to ${cwd}/${llnodeLib}`);
18+
child_process.execSync(`mv ${cwd}/out/Release/${llnodeLib} ${cwd}/${llnodeLib}`);
19+
20+
console.log(`${os.EOL}llnode plugin installed, load in lldb with:`);
21+
console.log(`(lldb) plugin load ${cwd}/${llnodeLib}${os.EOL}`);

scripts/configure.js

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
'use strict';
2+
3+
const os = require('os');
4+
const fs = require('fs');
5+
const child_process = require('child_process');
6+
7+
const lldbReleases = {
8+
'4.0': 'master',
9+
'3.9': 'release_39',
10+
'3.8': 'release_38',
11+
'3.7': 'release_37',
12+
'3.6': 'release_36',
13+
'3.5': 'release_35',
14+
'3.4': 'release_34',
15+
};
16+
17+
const buildDir = process.cwd();
18+
19+
console.log('Build dir is: ' + buildDir);
20+
21+
const osName = os.type();
22+
23+
var lldbVersion;
24+
var lldbHeadersBranch;
25+
var lldbIncludeDir;
26+
27+
// Need to determine:
28+
// - What level of lldb we are running.
29+
// - If we need the headers. (Linux may have them installed)
30+
var lldbExe = 'lldb';
31+
32+
if (osName === 'Darwin') {
33+
34+
lldbVersion = getDarwinRelease();
35+
36+
if (lldbVersion === undefined) {
37+
console.log('Unable to locate lldb binary. llnode installation failed.');
38+
process.exit(1);
39+
}
40+
41+
lldbHeadersBranch = lldbReleases[lldbVersion];
42+
lldbIncludeDir = 'lldb-' + lldbVersion;
43+
44+
} else if (osName === 'Linux') {
45+
46+
lldbExe = getLldbExecutable();
47+
lldbVersion = getLinuxVersion(lldbExe);
48+
49+
if (lldbVersion === undefined) {
50+
console.log('Unable to locate lldb binary. llnode installation failed.');
51+
process.exit(1);
52+
}
53+
54+
// console.log('lldb_version is ' + lldb_version)
55+
var installedHeadersDir = getLinuxHeadersDir(lldbVersion);
56+
// console.log('installed_headers_dir is ' + installed_headers_dir);
57+
if (installedHeadersDir === undefined) {
58+
// Initialising lldb_headers_branch will cause us to clone them.
59+
lldbHeadersBranch = lldbReleases[lldbVersion];
60+
lldbIncludeDir = 'lldb-' + lldbVersion;
61+
} else {
62+
lldbIncludeDir = installedHeadersDir;
63+
}
64+
}
65+
66+
console.log(`Installing llnode for ${lldbExe}, lldb version ${lldbVersion}`);
67+
68+
// Check out source code of the LLDB that is compatible with OS X's default lldb
69+
// TODO: The llvm project is probably moving to github soon at that point we
70+
// should stop using the mirror.
71+
if (lldbHeadersBranch != undefined) {
72+
console.log('Cloning lldb from ' + lldbHeadersBranch);
73+
child_process.execFileSync('git',
74+
['clone', '--depth=1', '-b', lldbHeadersBranch,
75+
'https://github.com/llvm-mirror/lldb.git', lldbIncludeDir],
76+
{cwd: buildDir});
77+
}
78+
79+
// Link to the headers file so we can run gyp_llnode directly and don't need to
80+
// setup parameters to pass it.
81+
console.log(`Linking lldb to include directory ${lldbIncludeDir}`);
82+
fs.symlinkSync(lldbIncludeDir, 'lldb');
83+
84+
// Initialize GYP
85+
// We can use the node-gyp that comes with npm.
86+
// We can locate it with npm -g explore npm npm explore node-gyp pwd
87+
// It might have been neater to make node-gyp one of our dependencies
88+
// *but* they don't get installed until after the install step has run.
89+
var gypDir = child_process.execFileSync('npm',
90+
['-g', 'explore', 'npm', 'npm', 'explore', 'node-gyp', 'pwd'],
91+
{cwd: buildDir}).toString().trim();
92+
fs.mkdirSync('tools');
93+
console.log(`Linking tools/gyp to ${gypDir}/gyp`);
94+
fs.symlinkSync(`${gypDir}/gyp`, 'tools/gyp');
95+
96+
// Exit with success.
97+
process.exit(0);
98+
99+
// On Mac the lldb version string doesn't match the original lldb versions.
100+
function getDarwinRelease() {
101+
var xcodeStr;
102+
try {
103+
xcodeStr = child_process.execFileSync('xcodebuild', ['-version'])
104+
.toString();
105+
} catch (err) {
106+
return undefined;
107+
}
108+
var versionStr = '';
109+
var splitStr = xcodeStr.split(os.EOL);
110+
for (var str of splitStr) {
111+
if (str.indexOf('Xcode') != -1) {
112+
versionStr = str.split(' ')[1];
113+
break;
114+
}
115+
}
116+
// console.log('Xcode version is ' + version_str)
117+
118+
var version = parseFloat(versionStr);
119+
if (version > 8.0) {
120+
return '3.8';
121+
} else {
122+
return '3.4';
123+
}
124+
}
125+
126+
// Find the 'best' lldb to use. Either:
127+
// - the one specified by the user using npm --llnode_exe=... install llnode
128+
// - the default lldb executable
129+
// - the higest known lldb version
130+
function getLldbExecutable() {
131+
var lldbExe = process.env.npm_config_lldb_exe;
132+
if (lldbExe === undefined) {
133+
var lldbExeNames = ['lldb', 'lldb-4.0', 'lldb-3.9',
134+
'lldb-3.8', 'lldb-3.7', 'lldb-3.6'];
135+
for (var lldbExeVersion of lldbExeNames) {
136+
try {
137+
lldbExe = child_process.execSync('which ' +
138+
lldbExeVersion).toString().trim();
139+
// If the result starts with '/' `which` found a path.
140+
if (lldbExe.startsWith('/')) {
141+
break;
142+
}
143+
} catch (err) {
144+
// Do nothing - we expect not to find some of these.
145+
}
146+
}
147+
}
148+
return lldbExe;
149+
}
150+
151+
// There are multiple versions of lldb available for the various linux distos.
152+
// Use the default unless --llnode_exe= has been set on the command line.
153+
function getLinuxVersion(lldbExe) {
154+
155+
var lldbStr;
156+
try {
157+
lldbStr = child_process.execFileSync(lldbExe, ['-v']).toString();
158+
} catch (err) {
159+
return undefined;
160+
}
161+
// Ignore minor revisions like 3.8.1
162+
if (lldbStr.indexOf('version 4.0') > 0) {
163+
return '4.0';
164+
} else if (lldbStr.indexOf('version 3.9') > 0) {
165+
return '3.9';
166+
} else if (lldbStr.indexOf('version 3.8') > 0) {
167+
return '3.8';
168+
} else if (lldbStr.indexOf('version 3.7') > 0) {
169+
return '3.7';
170+
} if (lldbStr.indexOf('version 3.6') > 0) {
171+
return '3.6';
172+
} if (lldbStr.indexOf('version 3.5') > 0) {
173+
return '3.5';
174+
}
175+
return undefined;
176+
}
177+
178+
function getLinuxHeadersDir(version) {
179+
// Get the directory which should contain the headers and
180+
// check if they are present.
181+
// (Using the installed headers will ensure we have the correct ones.)
182+
console.log('Checking for headers, version is ' + version);
183+
try {
184+
var includeDir = child_process.execFileSync('llvm-config-' + version,
185+
['--prefix']).toString().trim();
186+
// console.log('Checking for directory ' + include_dir);
187+
// Include directory doesn't need include/lldb on the end but the llvm
188+
// headers can be installed without the lldb headers so check for them.
189+
if (fs.existsSync(includeDir + '/include/lldb')) {
190+
// console.log('Found ' + include_dir);
191+
return includeDir;
192+
}
193+
} catch (err) {
194+
// Return undefined, we will download the headers.
195+
}
196+
// On Redhat the headers are just installed in /usr/include
197+
if (fs.existsSync('/usr/include/lldb')) {
198+
return '/usr';
199+
}
200+
return undefined;
201+
}

0 commit comments

Comments
 (0)