mirror of https://github.com/nodejs/node.git
installer: fix cross-compile installs
The old installer was a JS script, which didn't work if node had been cross-compiled for another architecture. Replace it with a python script. Fixes #3807.pull/24503/head
parent
34c750d7a9
commit
50e00de92a
4
Makefile
4
Makefile
|
@ -39,10 +39,10 @@ out/Makefile: common.gypi deps/uv/uv.gyp deps/http_parser/http_parser.gyp deps/z
|
|||
$(PYTHON) tools/gyp_node -f make
|
||||
|
||||
install: all
|
||||
out/Release/node tools/installer.js install $(DESTDIR)
|
||||
$(PYTHON) tools/install.py $@ $(DESTDIR)
|
||||
|
||||
uninstall:
|
||||
out/Release/node tools/installer.js uninstall
|
||||
$(PYTHON) tools/install.py $@ $(DESTDIR)
|
||||
|
||||
clean:
|
||||
-rm -rf out/Makefile node node_g out/$(BUILDTYPE)/node blog.html email.md
|
||||
|
|
|
@ -0,0 +1,214 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import errno
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
# set at init time
|
||||
dst_dir = None
|
||||
node_prefix = None # dst_dir without DESTDIR prefix
|
||||
target_defaults = None
|
||||
variables = None
|
||||
|
||||
def abspath(*args):
|
||||
path = os.path.join(*args)
|
||||
return os.path.abspath(path)
|
||||
|
||||
def load_config():
|
||||
s = open('config.gypi').read()
|
||||
s = re.sub(r'#.*?\n', '', s) # strip comments
|
||||
s = re.sub(r'\'', '"', s) # convert quotes
|
||||
return json.loads(s)
|
||||
|
||||
def try_unlink(path):
|
||||
try:
|
||||
os.unlink(path)
|
||||
except OSError, e:
|
||||
if e.errno != errno.ENOENT: raise
|
||||
|
||||
def try_symlink(source_path, link_path):
|
||||
print 'symlinking %s -> %s' % (source_path, link_path)
|
||||
try_unlink(link_path)
|
||||
os.symlink(source_path, link_path)
|
||||
|
||||
def try_mkdir_r(path):
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError, e:
|
||||
if e.errno != errno.EEXIST: raise
|
||||
|
||||
def try_rmdir_r(path):
|
||||
path = abspath(path)
|
||||
while path.startswith(dst_dir):
|
||||
try:
|
||||
os.rmdir(path)
|
||||
except OSError, e:
|
||||
if e.errno == errno.ENOTEMPTY: return
|
||||
if e.errno == errno.ENOENT: return
|
||||
raise
|
||||
path = abspath(path, '..')
|
||||
|
||||
def mkpaths(path, dst):
|
||||
if dst.endswith('/'):
|
||||
target_path = abspath(dst_dir, dst, os.path.basename(path))
|
||||
else:
|
||||
target_path = abspath(dst_dir, dst)
|
||||
return path, target_path
|
||||
|
||||
def try_copy(path, dst):
|
||||
source_path, target_path = mkpaths(path, dst)
|
||||
print 'installing %s' % target_path
|
||||
try_mkdir_r(os.path.dirname(target_path))
|
||||
return shutil.copy2(source_path, target_path)
|
||||
|
||||
def try_remove(path, dst):
|
||||
source_path, target_path = mkpaths(path, dst)
|
||||
print 'removing %s' % target_path
|
||||
try_unlink(target_path)
|
||||
try_rmdir_r(os.path.dirname(target_path))
|
||||
|
||||
def install(paths, dst): map(lambda path: try_copy(path, dst), paths)
|
||||
def uninstall(paths, dst): map(lambda path: try_remove(path, dst), paths)
|
||||
|
||||
def waf_files(action):
|
||||
action(['tools/node-waf'], 'bin/node-waf')
|
||||
action(['tools/wafadmin/ansiterm.py',
|
||||
'tools/wafadmin/Build.py',
|
||||
'tools/wafadmin/Configure.py',
|
||||
'tools/wafadmin/Constants.py',
|
||||
'tools/wafadmin/Environment.py',
|
||||
'tools/wafadmin/__init__.py',
|
||||
'tools/wafadmin/Logs.py',
|
||||
'tools/wafadmin/Node.py',
|
||||
'tools/wafadmin/Options.py',
|
||||
'tools/wafadmin/pproc.py',
|
||||
'tools/wafadmin/py3kfixes.py',
|
||||
'tools/wafadmin/Runner.py',
|
||||
'tools/wafadmin/Scripting.py',
|
||||
'tools/wafadmin/TaskGen.py',
|
||||
'tools/wafadmin/Task.py',
|
||||
'tools/wafadmin/Tools/ar.py',
|
||||
'tools/wafadmin/Tools/cc.py',
|
||||
'tools/wafadmin/Tools/ccroot.py',
|
||||
'tools/wafadmin/Tools/compiler_cc.py',
|
||||
'tools/wafadmin/Tools/compiler_cxx.py',
|
||||
'tools/wafadmin/Tools/compiler_d.py',
|
||||
'tools/wafadmin/Tools/config_c.py',
|
||||
'tools/wafadmin/Tools/cxx.py',
|
||||
'tools/wafadmin/Tools/dmd.py',
|
||||
'tools/wafadmin/Tools/d.py',
|
||||
'tools/wafadmin/Tools/gas.py',
|
||||
'tools/wafadmin/Tools/gcc.py',
|
||||
'tools/wafadmin/Tools/gdc.py',
|
||||
'tools/wafadmin/Tools/gnu_dirs.py',
|
||||
'tools/wafadmin/Tools/gob2.py',
|
||||
'tools/wafadmin/Tools/gxx.py',
|
||||
'tools/wafadmin/Tools/icc.py',
|
||||
'tools/wafadmin/Tools/icpc.py',
|
||||
'tools/wafadmin/Tools/__init__.py',
|
||||
'tools/wafadmin/Tools/intltool.py',
|
||||
'tools/wafadmin/Tools/libtool.py',
|
||||
'tools/wafadmin/Tools/misc.py',
|
||||
'tools/wafadmin/Tools/nasm.py',
|
||||
'tools/wafadmin/Tools/node_addon.py',
|
||||
'tools/wafadmin/Tools/osx.py',
|
||||
'tools/wafadmin/Tools/preproc.py',
|
||||
'tools/wafadmin/Tools/python.py',
|
||||
'tools/wafadmin/Tools/suncc.py',
|
||||
'tools/wafadmin/Tools/suncxx.py',
|
||||
'tools/wafadmin/Tools/unittestw.py',
|
||||
'tools/wafadmin/Tools/winres.py',
|
||||
'tools/wafadmin/Tools/xlc.py',
|
||||
'tools/wafadmin/Tools/xlcxx.py',
|
||||
'tools/wafadmin/Utils.py'],
|
||||
'lib/node/')
|
||||
|
||||
def update_shebang(path, shebang):
|
||||
print 'updating shebang of %s' % path
|
||||
s = open(path, 'r').read()
|
||||
s = re.sub(r'#!.*\n', '#!' + shebang + '\n', s)
|
||||
open(path, 'w').write(s)
|
||||
|
||||
def npm_files(action):
|
||||
target_path = 'lib/node_modules/npm/'
|
||||
|
||||
# don't install npm if the target path is a symlink, it probably means
|
||||
# that a dev version of npm is installed there
|
||||
if os.path.islink(abspath(dst_dir, target_path)): return
|
||||
|
||||
# npm has a *lot* of files and it'd be a pain to maintain a fixed list here
|
||||
# so we walk its source directory instead...
|
||||
for dirname, subdirs, basenames in os.walk('deps/npm', topdown=True):
|
||||
subdirs[:] = filter('test'.__ne__, subdirs) # skip test suites
|
||||
paths = [os.path.join(dirname, basename) for basename in basenames]
|
||||
action(paths, target_path + dirname[9:] + '/')
|
||||
|
||||
# create/remove symlink
|
||||
link_path = abspath(dst_dir, 'bin/npm')
|
||||
if action == uninstall:
|
||||
action([link_path], 'bin/npm')
|
||||
elif action == install:
|
||||
try_symlink('../lib/node_modules/npm/bin/npm-cli.js', link_path)
|
||||
update_shebang(link_path, node_prefix + '/bin/node')
|
||||
else:
|
||||
assert(0) # unhandled action type
|
||||
|
||||
def files(action):
|
||||
action(['deps/uv/include/ares.h',
|
||||
'deps/uv/include/ares_version.h',
|
||||
'deps/uv/include/uv.h',
|
||||
'deps/v8/include/v8-debug.h',
|
||||
'deps/v8/include/v8-preparser.h',
|
||||
'deps/v8/include/v8-profiler.h',
|
||||
'deps/v8/include/v8-testing.h',
|
||||
'deps/v8/include/v8.h',
|
||||
'deps/v8/include/v8stdint.h',
|
||||
'src/eio-emul.h',
|
||||
'src/ev-emul.h',
|
||||
'src/node.h',
|
||||
'src/node_buffer.h',
|
||||
'src/node_object_wrap.h',
|
||||
'src/node_version.h'],
|
||||
'include/node/')
|
||||
action(['deps/uv/include/uv-private/eio.h',
|
||||
'deps/uv/include/uv-private/ev.h',
|
||||
'deps/uv/include/uv-private/ngx-queue.h',
|
||||
'deps/uv/include/uv-private/tree.h',
|
||||
'deps/uv/include/uv-private/uv-unix.h',
|
||||
'deps/uv/include/uv-private/uv-win.h'],
|
||||
'include/node/uv-private/')
|
||||
action(['doc/node.1'], 'share/man/man1/')
|
||||
action(['out/Release/node'], 'bin/node')
|
||||
|
||||
# install unconditionally, checking if the platform supports dtrace doesn't
|
||||
# work when cross-compiling and besides, there's at least one linux flavor
|
||||
# with dtrace support now (oracle's "unbreakable" linux)
|
||||
action(['src/node.d'], 'lib/dtrace/')
|
||||
|
||||
if variables.get('node_install_waf'): waf_files(action)
|
||||
if variables.get('node_install_npm'): npm_files(action)
|
||||
|
||||
def run(args):
|
||||
global dst_dir, node_prefix, target_defaults, variables
|
||||
|
||||
# chdir to the project's top-level directory
|
||||
os.chdir(abspath(os.path.dirname(__file__), '..'))
|
||||
|
||||
conf = load_config()
|
||||
variables = conf['variables']
|
||||
target_defaults = conf['target_defaults']
|
||||
|
||||
# argv[2] is a custom install prefix for packagers (think DESTDIR)
|
||||
dst_dir = node_prefix = variables.get('node_prefix', '/usr/local')
|
||||
if len(args) > 2: dst_dir = abspath(args[2] + '/' + dst_dir)
|
||||
|
||||
cmd = args[1] if len(args) > 1 else 'install'
|
||||
if cmd == 'install': return files(install)
|
||||
if cmd == 'uninstall': return files(uninstall)
|
||||
raise RuntimeError('Bad command: %s\n' % cmd)
|
||||
|
||||
if __name__ == '__main__':
|
||||
run(sys.argv[:])
|
|
@ -1,158 +0,0 @@
|
|||
var fs = require('fs'),
|
||||
path = require('path'),
|
||||
exec = require('child_process').exec,
|
||||
cmd = process.argv[2],
|
||||
dest_dir = process.argv[3] || '';
|
||||
|
||||
if (cmd !== 'install' && cmd !== 'uninstall') {
|
||||
console.error('Unknown command: ' + cmd);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Use the built-in config reported by the current process
|
||||
var variables = process.config.variables,
|
||||
node_prefix = variables.node_prefix || '/usr/local';
|
||||
|
||||
// Execution queue
|
||||
var queue = [],
|
||||
dirs = [];
|
||||
|
||||
// Copy file from src to dst
|
||||
function copy(src, dst, callback) {
|
||||
// If src is array - copy each file separately
|
||||
if (Array.isArray(src)) {
|
||||
src.forEach(function(src) {
|
||||
copy(src, dst, callback);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
dst = path.join(dest_dir, node_prefix, dst);
|
||||
var dir = dst.replace(/\/[^\/]*$/, '/');
|
||||
|
||||
// Create directory if hasn't done this yet
|
||||
if (dirs.indexOf(dir) === -1) {
|
||||
dirs.push(dir);
|
||||
queue.push('mkdir -p ' + dir);
|
||||
}
|
||||
|
||||
// Queue file/dir copy
|
||||
queue.push('cp -rf ' + src + ' ' + dst);
|
||||
}
|
||||
|
||||
// Remove files
|
||||
function remove(files) {
|
||||
files.forEach(function(file) {
|
||||
file = path.join(dest_dir, node_prefix, file);
|
||||
queue.push('rm -rf ' + file);
|
||||
});
|
||||
}
|
||||
|
||||
// Add/update shebang (#!) line so that npm uses
|
||||
// the newly installed node, rather than the first in PATH.
|
||||
function shebang(line, npmDir) {
|
||||
var script = JSON.stringify(path.join(npmDir, 'scripts/relocate.sh'));
|
||||
var bin = JSON.stringify(path.join(npmDir, 'bin/npm-cli.js'));
|
||||
queue.push('/bin/sh ' + script + ' ' + line);
|
||||
}
|
||||
|
||||
// Run every command in queue, one-by-one
|
||||
function run() {
|
||||
var cmd = queue.shift();
|
||||
if (!cmd) return;
|
||||
|
||||
if (Array.isArray(cmd) && cmd[0] instanceof Function) {
|
||||
var func = cmd[0];
|
||||
var args = cmd.slice(1);
|
||||
console.log.apply(null, [func.name].concat(args));
|
||||
func.apply(null, args);
|
||||
run();
|
||||
} else {
|
||||
console.log(cmd);
|
||||
exec(cmd, function(err, stdout, stderr) {
|
||||
if (stderr) console.error(stderr);
|
||||
if (err) process.exit(1);
|
||||
|
||||
run();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd === 'install') {
|
||||
// Copy includes
|
||||
copy([
|
||||
// Node
|
||||
'src/node.h', 'src/node_buffer.h', 'src/node_object_wrap.h',
|
||||
'src/node_version.h', 'src/ev-emul.h', 'src/eio-emul.h',
|
||||
// v8
|
||||
'deps/v8/include/v8-debug.h', 'deps/v8/include/v8-preparser.h',
|
||||
'deps/v8/include/v8-profiler.h', 'deps/v8/include/v8-testing.h',
|
||||
'deps/v8/include/v8.h', 'deps/v8/include/v8stdint.h',
|
||||
// uv
|
||||
'deps/uv/include/uv.h'
|
||||
], 'include/node/');
|
||||
|
||||
// man page
|
||||
copy(['doc/node.1'], 'share/man/man1/');
|
||||
|
||||
// dtrace
|
||||
if (!process.platform.match(/^linux/)) {
|
||||
copy(['src/node.d'], 'lib/dtrace/');
|
||||
}
|
||||
|
||||
// Private uv headers
|
||||
copy([
|
||||
'deps/uv/include/uv-private/eio.h', 'deps/uv/include/uv-private/ev.h',
|
||||
'deps/uv/include/uv-private/ngx-queue.h',
|
||||
'deps/uv/include/uv-private/tree.h',
|
||||
'deps/uv/include/uv-private/uv-unix.h',
|
||||
'deps/uv/include/uv-private/uv-win.h',
|
||||
], 'include/node/uv-private/');
|
||||
|
||||
copy([
|
||||
'deps/uv/include/ares.h',
|
||||
'deps/uv/include/ares_version.h'
|
||||
], 'include/node/');
|
||||
|
||||
// Copy binary file
|
||||
copy('out/Release/node', 'bin/node');
|
||||
|
||||
// Install node-waf
|
||||
if (variables.node_install_waf) {
|
||||
copy('tools/wafadmin', 'lib/node/');
|
||||
copy('tools/node-waf', 'bin/node-waf');
|
||||
}
|
||||
|
||||
// Install npm (eventually)
|
||||
if (variables.node_install_npm) {
|
||||
// Frequently, in development, the installed npm is a symbolic
|
||||
// link to the development folder, and so installing this is
|
||||
// a bit annoying. If it's a symlink, skip it.
|
||||
var isSymlink = false;
|
||||
var exists = true;
|
||||
var npmDir = path.resolve(node_prefix, 'lib/node_modules/npm');
|
||||
try {
|
||||
var st = fs.lstatSync(npmDir);
|
||||
isSymlink = st.isSymbolicLink();
|
||||
} catch (e) {
|
||||
exists = true;
|
||||
}
|
||||
|
||||
if (!isSymlink) {
|
||||
if (exists) queue.push('rm -rf ' + npmDir);
|
||||
copy('deps/npm', 'lib/node_modules/npm');
|
||||
queue.push('ln -sf ../lib/node_modules/npm/bin/npm-cli.js ' +
|
||||
path.join(dest_dir, node_prefix, 'bin/npm'));
|
||||
shebang(path.join(node_prefix, 'bin/node'),
|
||||
path.join(dest_dir, node_prefix, 'lib/node_modules/npm'));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
remove([
|
||||
'bin/node', 'bin/npm', 'bin/node-waf',
|
||||
'include/node/*', 'lib/node_modules', 'lib/node',
|
||||
'lib/dtrace/node.d', 'share/man/man1/node.1'
|
||||
]);
|
||||
}
|
||||
|
||||
run();
|
Loading…
Reference in New Issue