[pypy-commit] pypy default: add a --make-portable option to package.py
mattip
pypy.commits at gmail.com
Fri Nov 1 17:43:14 EDT 2019
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r97930:b655ef00bd4b
Date: 2019-11-01 05:52 -0400
http://bitbucket.org/pypy/pypy/changeset/b655ef00bd4b/
Log: add a --make-portable option to package.py
diff --git a/pypy/tool/release/make_portable.py b/pypy/tool/release/make_portable.py
new file mode 100644
--- /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
--- a/pypy/tool/release/package.py
+++ b/pypy/tool/release/package.py
@@ -235,7 +235,11 @@
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 @@
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 @@
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
More information about the pypy-commit
mailing list