diff options
author | Matti Picus <matti.picus@gmail.com> | 2019-11-01 05:52:35 -0400 |
---|---|---|
committer | Matti Picus <matti.picus@gmail.com> | 2019-11-01 05:52:35 -0400 |
commit | 3f4cd2f19d083b7a74889dbefd5ab78478ad023c (patch) | |
tree | edaea6c9c6cab2392601f4dc278d9692d1d0470a /pypy/tool | |
parent | make print in package.py 3-compatible (diff) | |
download | pypy-3f4cd2f19d083b7a74889dbefd5ab78478ad023c.tar.gz pypy-3f4cd2f19d083b7a74889dbefd5ab78478ad023c.tar.bz2 pypy-3f4cd2f19d083b7a74889dbefd5ab78478ad023c.zip |
add a --make-portable option to package.py
Diffstat (limited to 'pypy/tool')
-rw-r--r-- | pypy/tool/release/make_portable.py | 109 | ||||
-rwxr-xr-x | pypy/tool/release/package.py | 16 |
2 files changed, 124 insertions, 1 deletions
diff --git a/pypy/tool/release/make_portable.py b/pypy/tool/release/make_portable.py new file mode 100644 index 0000000000..691ee10cb2 --- /dev/null +++ b/pypy/tool/release/make_portable.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python + +bundle = ['sqlite3', 'ssl', 'crypto', 'ffi', 'expat', 'tcl', 'tk', 'gdbm', 'lzma', 'ncursesw', 'panelw', 'tinfow'] + +from os import chdir, mkdir, symlink +from os.path import dirname, relpath, join, exists, basename, realpath +from shutil import copy2 +import sys +from glob import glob +from subprocess import check_output, check_call + + +def get_deps(binary): + deps = {} + output = check_output(['ldd', binary]) + for line in output.splitlines(): + if '=>' not in line: + continue + line = line.strip() + needed, path = line.split(' => ') + if path == 'not found': + print('Broken dependency in ' + binary) + path = path.split(' ')[0] + path = realpath(path) + if not path: + continue + + if needed[3:].split('.', 1)[0] not in bundle: + continue + + deps[needed] = path + deps.update(get_deps(path)) + + return deps + + +def gather_deps(binaries): + deps = {} + for binary in binaries: + deps.update(get_deps(binary)) + + return deps + + +def copy_deps(deps): + copied = {} + + for needed, path in deps.items(): + bname = basename(path) + + copy2(path, 'lib/' + bname) + copied[path] = 'lib/' + bname + + if not exists('lib/' + needed): + symlink(bname, 'lib/' + needed) + + return copied + + +def rpath_binaries(binaries): + rpaths = {} + + for binary in binaries: + rpath = join('$ORIGIN', relpath('lib', dirname(binary))) + check_call(['patchelf', '--set-rpath', rpath, binary]) + + rpaths[binary] = rpath + + return rpaths + + +def make_portable(): + binaries = glob('bin/libpypy*.so') + if not binaries: + raise ValueError('Could not find bin/libpypy*.so') + binaries.extend(glob('lib_pypy/*_cffi.pypy*.so')) + binaries.extend(glob('lib_pypy/_pypy_openssl*.so')) + binaries.extend(glob('lib_pypy/_tkinter/*_cffi.pypy*.so')) + + deps = gather_deps(binaries) + + copied = copy_deps(deps) + + for path, item in copied.items(): + print('Copied {0} to {1}'.format(path, item)) + + binaries.extend(copied.values()) + + rpaths = rpath_binaries(binaries) + for binary, rpath in rpaths.items(): + print('Set RPATH of {0} to {1}'.format(binary, rpath)) + + return deps + + +if __name__ == '__main__': + try: + chdir(sys.argv[1]) + except: + print('Call as %s <path/to/pypy/topdir' % sys.argv[0]) + exit(-1) + + try: + mkdir('lib') + except OSError: + pass + + make_portable() + diff --git a/pypy/tool/release/package.py b/pypy/tool/release/package.py index 48bfe9db0c..721b1fac43 100755 --- a/pypy/tool/release/package.py +++ b/pypy/tool/release/package.py @@ -235,7 +235,11 @@ def create_package(basedir, options, _fake=False): else: archive = bindir.join(target) smartstrip(archive, keep_debug=options.keep_debug) - # + + # make the package portable by adding rpath=$ORIGIN/..lib, + # bundling dependencies + if options.make_portable: + make_portable() if USE_ZIPFILE_MODULE: import zipfile archive = str(builddir.join(name + '.zip')) @@ -319,6 +323,12 @@ def package(*args, **kwds): default=(sys.platform == 'darwin'), help='whether to embed dependencies in CFFI modules ' '(default on OS X)') + parser.add_argument('--make-portable', '--no-make-portable', + dest='make_portable', + action=NegateAction, + default=(platform.linux_distribution() in ('CentOS',)), + help='whether to make the package portable by shipping ' + 'dependent shared objects and mangling RPATH') options = parser.parse_args(args) if os.environ.has_key("PYPY_PACKAGE_NOKEEPDEBUG"): @@ -329,6 +339,10 @@ def package(*args, **kwds): options.embed_dependencies = True elif os.environ.has_key("PYPY_NO_EMBED_DEPENDENCIES"): options.embed_dependencies = False + if os.environ.has_key("PYPY_MAKE_PORTABLE"): + options.embed_dependencies = True + elif os.environ.has_key("PYPY_NO_MAKE_PORTABLE"): + options.embed_dependencies = False if not options.builddir: # The import actually creates the udir directory from rpython.tool.udir import udir |