aboutsummaryrefslogtreecommitdiff
path: root/pypy/tool
diff options
context:
space:
mode:
authorMatti Picus <matti.picus@gmail.com>2019-11-01 05:52:35 -0400
committerMatti Picus <matti.picus@gmail.com>2019-11-01 05:52:35 -0400
commit3f4cd2f19d083b7a74889dbefd5ab78478ad023c (patch)
treeedaea6c9c6cab2392601f4dc278d9692d1d0470a /pypy/tool
parentmake print in package.py 3-compatible (diff)
downloadpypy-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.py109
-rwxr-xr-xpypy/tool/release/package.py16
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