├── env.list ├── _curses_build.py.2.patch ├── virtualenv-pypy ├── _curses_build.py.patch ├── subprocess.py.patch ├── subprocess3.py.patch ├── sysconfig_pypy3.py.patch ├── sysconfig_pypy.py.patch ├── image └── Dockerfile ├── _tkinter_app.py.patch ├── version.py ├── test_ssl_trust.py ├── platform_linux.patch ├── socket.append.py ├── runopt.sh ├── LICENSE ├── BUILD.rst ├── package ├── ssl.py.patch ├── ssl3.py.patch ├── make_portable └── README.rst /env.list: -------------------------------------------------------------------------------- 1 | PATH=/opt/devtools-8.2/bin:/opt/prefix/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 2 | CFLAGS=-D__USE_XOPEN2K8 -I/opt/prefix/include -I/opt/prefix/include/ncursesw 3 | CXXFLAGS=-D__USE_XOPEN2K8 4 | CPPFLAGS=-I/opt/prefix/include 5 | LDFLAGS=-L/opt/prefix/lib -Wl,-rpath,/opt/prefix/lib 6 | PYPY_USESSION_DIR=/src 7 | -------------------------------------------------------------------------------- /_curses_build.py.2.patch: -------------------------------------------------------------------------------- 1 | --- lib_pypy/_curses_build.py.orig 2017-12-28 21:40:02.329433636 +0100 2 | +++ lib_pypy/_curses_build.py 2017-12-28 21:40:17.128547172 +0100 3 | @@ -41,7 +41,7 @@ 4 | void _m_getsyx(int *yx) { 5 | getsyx(yx[0], yx[1]); 6 | } 7 | -""", libraries=['ncurses', 'panel']) 8 | +""", libraries=['ncursesw', 'panelw']) 9 | 10 | 11 | ffi.cdef(""" 12 | -------------------------------------------------------------------------------- /virtualenv-pypy: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """This is a trampoline file to make it work on Python 2.4""" 4 | 5 | from os.path import realpath, join, dirname 6 | from subprocess import call 7 | from sys import argv 8 | 9 | here = dirname(realpath(__file__)) 10 | pypy = join(here, 'pypy') 11 | virtualenv = join(here, '../virtualenv/virtualenv.py') 12 | 13 | call([pypy, virtualenv] + argv[1:]) 14 | -------------------------------------------------------------------------------- /_curses_build.py.patch: -------------------------------------------------------------------------------- 1 | --- lib_pypy/_curses_build.py.orig 2017-12-28 20:08:20.833459790 +0100 2 | +++ lib_pypy/_curses_build.py 2017-12-28 20:09:02.802801349 +0100 3 | @@ -65,7 +65,7 @@ 4 | void _m_getsyx(int *yx) { 5 | getsyx(yx[0], yx[1]); 6 | } 7 | -""", libraries=[find_curses_library(), 'panel'], 8 | +""", libraries=[find_curses_library(), 'panelw'], 9 | include_dirs=find_curses_include_dirs()) 10 | 11 | 12 | -------------------------------------------------------------------------------- /subprocess.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/2.7/subprocess_orig.py 2015-02-04 22:46:09.202287258 +0100 2 | +++ lib-python/2.7/subprocess.py 2015-02-04 23:05:27.208206464 +0100 3 | @@ -1595,6 +1595,11 @@ 4 | if os.path.exists(src_library): 5 | caller.f_globals['copyfile'](src_library, dest_library) 6 | 7 | + import shutil 8 | + shutil.copytree( 9 | + os.path.join(src_dir, '../lib'), 10 | + os.path.join(dest_dir, '../lib')) 11 | + 12 | 13 | def _demo_posix(): 14 | # 15 | -------------------------------------------------------------------------------- /subprocess3.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/3/subprocess.py.orig 2016-06-02 19:44:52.060004669 +0200 2 | +++ lib-python/3/subprocess.py 2016-06-02 19:46:49.860652037 +0200 3 | @@ -1817,3 +1817,8 @@ 4 | src_library = os.path.join(src_dir, libname) 5 | if os.path.exists(src_library): 6 | caller.f_globals['copyfile'](src_library, dest_library) 7 | + 8 | + import shutil 9 | + shutil.copytree( 10 | + os.path.join(src_dir, '../lib'), 11 | + os.path.join(dest_dir, '../lib')) 12 | -------------------------------------------------------------------------------- /sysconfig_pypy3.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/3/distutils/sysconfig_pypy.orig.py 2017-02-28 04:47:31.124383391 +0000 2 | +++ lib-python/3/distutils/sysconfig_pypy.py 2017-02-28 04:48:17.815045573 +0000 3 | @@ -189,6 +189,9 @@ 4 | else: 5 | archiver = ar + ' ' + ar_flags 6 | 7 | + libdir = os.path.join(sys.prefix, 'lib') 8 | + ldshared = ldshared + ' -L' + libdir + ' -Wl,-rpath,' + libdir 9 | + 10 | cc_cmd = cc + ' ' + cflags 11 | compiler.set_executables( 12 | preprocessor=cpp, 13 | -------------------------------------------------------------------------------- /sysconfig_pypy.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/2.7/distutils/sysconfig_pypy.orig.py 2017-04-04 14:41:03.829620959 +0000 2 | +++ lib-python/2.7/distutils/sysconfig_pypy.py 2017-04-04 14:42:24.221028972 +0000 3 | @@ -206,6 +206,9 @@ 4 | else: 5 | archiver = ar + ' ' + ar_flags 6 | 7 | + libdir = os.path.join(sys.prefix, 'lib') 8 | + ldshared = ldshared + ' -L' + libdir + ' -Wl,-rpath,' + libdir 9 | + 10 | cc_cmd = cc + ' ' + cflags 11 | compiler.set_executables( 12 | preprocessor=cpp, 13 | 14 | -------------------------------------------------------------------------------- /image/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/pypa/manylinux2010_x86_64 2 | 3 | RUN yum install -y wget make bzip2-devel zlib-devel glibc-devel libX11-devel libXt-devel patch expat libXft-devel perl 4 | 5 | RUN wget https://github.com/squeaky-pl/centos-devtools/releases/download/8.2-s1/gcc-8.2.0-binutils-2.32-x86_64.tar.bz2 -O - | tar -C / -xj 6 | RUN wget https://bitbucket.org/squeaky/portable-pypy/downloads/pypy-7.0.0-linux_x86_64-portable.tar.bz2 -O - | tar -C /opt -xj 7 | RUN mkdir -p /opt/pypy/bin 8 | RUN ln -s /opt/pypy-7.0.0-linux_x86_64-portable/bin/pypy /opt/pypy/bin/python 9 | 10 | -------------------------------------------------------------------------------- /_tkinter_app.py.patch: -------------------------------------------------------------------------------- 1 | --- original 2013-11-14 13:36:07.352264248 +0100 2 | +++ changed 2013-11-14 13:37:25.980266117 +0100 3 | @@ -29,6 +29,13 @@ 4 | 5 | 6 | def Tcl_AppInit(app): 7 | + from os.path import join, dirname 8 | + lib_path = join(dirname(dirname(dirname(__file__))), 'lib') 9 | + tcl_path = join(lib_path, 'tcl') 10 | + tk_path = join(lib_path, 'tk') 11 | + tklib.Tcl_Eval(app.interp, 'set tcl_library "{0}"'.format(tcl_path).encode('utf-8')) 12 | + tklib.Tcl_Eval(app.interp, 'set tk_library "{0}"'.format(tk_path).encode('utf-8')) 13 | + 14 | if tklib.Tcl_Init(app.interp) == tklib.TCL_ERROR: 15 | app.raiseTclError() 16 | skip_tk_init = tklib.Tcl_GetVar( 17 | -------------------------------------------------------------------------------- /version.py: -------------------------------------------------------------------------------- 1 | from sys import version_info, pypy_version_info as vi 2 | 3 | try: 4 | from sys import maxint 5 | except ImportError: 6 | from sys import maxsize as maxint 7 | 8 | import platform 9 | 10 | py = str(version_info[0]) + '.' + str(version_info[1]) if version_info[0] == 3 else '' 11 | 12 | name = 'pypy' + py + '-' + '.'.join(map(str, vi[:3])) 13 | 14 | if vi.releaselevel != 'final': 15 | name += '-' + vi.releaselevel 16 | 17 | if vi.serial: 18 | name += str(vi.serial) 19 | 20 | if vi.releaselevel == 'alpha': 21 | from datetime import datetime 22 | name += '-' + datetime.now().strftime('%Y%m%d') 23 | 24 | machine = 'x86_64' if maxint > 2**31 - 1 else 'i686' 25 | 26 | name += '-linux_' + machine + '-portable' 27 | 28 | print(name) 29 | -------------------------------------------------------------------------------- /test_ssl_trust.py: -------------------------------------------------------------------------------- 1 | import ssl 2 | import sys 3 | print(ssl.get_default_verify_paths()) 4 | 5 | context = ssl.create_default_context() 6 | 7 | import socket 8 | 9 | 10 | 11 | conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname="www.python.org") 12 | conn.connect(("www.python.org", 443)) 13 | print('OK https://www.python.org [Verified]') 14 | conn.close() 15 | 16 | 17 | conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname="untrusted-root.badssl.com") 18 | try: 19 | conn.connect(("untrusted-root.badssl.com", 443)) 20 | except ssl.SSLError: 21 | print('OK https://untrusted-root.badssl.com [Unverified]') 22 | else: 23 | print('FAIL https://untrusted-root.badssl.com [Verified]') 24 | sys.exit(1) 25 | finally: 26 | conn.close() 27 | -------------------------------------------------------------------------------- /platform_linux.patch: -------------------------------------------------------------------------------- 1 | --- rpython/translator/platform/linux_orig.py 2015-01-02 01:00:05.354058668 +0100 2 | +++ rpython/translator/platform/linux.py 2015-01-02 01:00:43.276964050 +0100 3 | @@ -26,14 +26,12 @@ 4 | 5 | def _include_dirs_for_libffi(self): 6 | return self._pkg_config("libffi", "--cflags-only-I", 7 | - ['/usr/include/libffi'], 8 | - check_result_dir=True) 9 | + ['/usr/include/libffi']) 10 | 11 | def _library_dirs_for_libffi(self): 12 | return self._pkg_config("libffi", "--libs-only-L", 13 | - ['/usr/lib/libffi'], 14 | - check_result_dir=True) 15 | - 16 | + ['/usr/lib/libffi']) 17 | + 18 | 19 | class Linux(BaseLinux): 20 | if platform.machine().startswith('arm'): 21 | -------------------------------------------------------------------------------- /socket.append.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def _add_lazy_options(): 4 | options = [ 5 | ('SO_BINDTODEVICE', 25, (3, 8)), 6 | ('SO_DOMAIN', 39, (2, 6, 32)), 7 | ('SO_MARK', 36, (2, 6, 25)), 8 | ('SO_PROTOCOL', 38, (2, 6, 32)), 9 | ('SO_REUSEPORT', 15, (3, 9)) 10 | ] 11 | 12 | def safe_int(v): 13 | try: 14 | return int(v) 15 | except ValueError: 16 | return 0 17 | 18 | import platform 19 | 20 | kern_version = platform.release().partition('-')[0] 21 | kern_version = kern_version.replace('.', ' ').replace('_', ' ') 22 | kern_version = tuple(map(safe_int, kern_version.split())) 23 | 24 | for name, value, version in options: 25 | if name in globals(): 26 | continue 27 | 28 | if kern_version >= version: 29 | globals()[name] = value 30 | 31 | _add_lazy_options() 32 | del _add_lazy_options 33 | 34 | -------------------------------------------------------------------------------- /runopt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | cat </dev/null 2>&1 77 | 78 | rm -f ${NAME}.tar.bz2 79 | tar -cjf ${NAME}.tar.bz2 $NAME 80 | 81 | md5sum ${NAME}.tar.bz2 82 | sha1sum ${NAME}.tar.bz2 83 | sha256sum ${NAME}.tar.bz2 84 | -------------------------------------------------------------------------------- /ssl.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/2.7/ssl.orig.py 2016-08-28 02:28:24.000000000 -0300 2 | +++ lib-python/2.7/ssl.py 2016-09-06 14:33:42.917950566 -0300 3 | @@ -278,6 +278,25 @@ 4 | "subjectAltName fields were found") 5 | 6 | 7 | +_cafile = None 8 | +_capath = None 9 | + 10 | +# https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/ 11 | +def _find_cafile_and_capath(): 12 | + global _cafile 13 | + global _capath 14 | + 15 | + if not _cafile and not _capath: 16 | + if os.path.isfile('/etc/pki/tls/certs/ca-bundle.crt'): 17 | + _cafile = '/etc/pki/tls/certs/ca-bundle.crt' 18 | + elif os.path.isdir('/etc/ssl/certs'): 19 | + _capath = '/etc/ssl/certs' 20 | + else: 21 | + _cafile = os.path.dirname(__file__) + '/cacert.pem' 22 | + 23 | + return _cafile, _capath 24 | + 25 | + 26 | DefaultVerifyPaths = namedtuple("DefaultVerifyPaths", 27 | "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env " 28 | "openssl_capath") 29 | @@ -285,14 +304,19 @@ 30 | def get_default_verify_paths(): 31 | """Return paths to default cafile and capath. 32 | """ 33 | - parts = _ssl.get_default_verify_paths() 34 | + parts = list(_ssl.get_default_verify_paths()) 35 | + cafile, capath = _find_cafile_and_capath() 36 | 37 | # environment vars shadow paths 38 | - cafile = os.environ.get(parts[0], parts[1]) 39 | - capath = os.environ.get(parts[2], parts[3]) 40 | + cafile = os.environ.get(parts[0], cafile) 41 | + capath = os.environ.get(parts[2], capath) 42 | + 43 | + # overwrite what we get from bundled openssl since it's useless 44 | + parts[1] = None 45 | + parts[3] = None 46 | 47 | - return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None, 48 | - capath if os.path.isdir(capath) else None, 49 | + return DefaultVerifyPaths(cafile if os.path.isfile(cafile or '') else None, 50 | + capath if os.path.isdir(capath or '') else None, 51 | *parts) 52 | 53 | 54 | @@ -389,7 +413,12 @@ 55 | if sys.platform == "win32": 56 | for storename in self._windows_cert_stores: 57 | self._load_windows_store_certs(storename, purpose) 58 | - self.set_default_verify_paths() 59 | + 60 | + if not os.environ.get('SSL_CERT_FILE') and not os.environ.get('SSL_CERT_DIR'): 61 | + locations = _find_cafile_and_capath() 62 | + self.load_verify_locations(*locations) 63 | + else: 64 | + self.set_default_verify_paths() 65 | 66 | 67 | def create_default_context(purpose=Purpose.SERVER_AUTH, cafile=None, 68 | -------------------------------------------------------------------------------- /ssl3.py.patch: -------------------------------------------------------------------------------- 1 | --- lib-python/3/ssl.orig.py 2017-02-28 03:45:33.984894721 +0000 2 | +++ lib-python/3/ssl.py 2017-02-28 03:53:46.021192608 +0000 3 | @@ -312,6 +312,27 @@ 4 | "subjectAltName fields were found") 5 | 6 | 7 | + 8 | +_cafile = None 9 | +_capath = None 10 | + 11 | +# https://www.happyassassin.net/2015/01/12/a-note-about-ssltls-trusted-certificate-stores-and-platforms/ 12 | +def _find_cafile_and_capath(): 13 | + global _cafile 14 | + global _capath 15 | + 16 | + if not _cafile and not _capath: 17 | + if os.path.isfile('/etc/pki/tls/certs/ca-bundle.crt'): 18 | + _cafile = '/etc/pki/tls/certs/ca-bundle.crt' 19 | + elif os.path.isdir('/etc/ssl/certs'): 20 | + _capath = '/etc/ssl/certs' 21 | + else: 22 | + _cafile = os.path.dirname(__file__) + '/cacert.pem' 23 | + 24 | + return _cafile, _capath 25 | + 26 | + 27 | + 28 | DefaultVerifyPaths = namedtuple("DefaultVerifyPaths", 29 | "cafile capath openssl_cafile_env openssl_cafile openssl_capath_env " 30 | "openssl_capath") 31 | @@ -319,14 +340,19 @@ 32 | def get_default_verify_paths(): 33 | """Return paths to default cafile and capath. 34 | """ 35 | - parts = _ssl.get_default_verify_paths() 36 | - 37 | + parts = list(_ssl.get_default_verify_paths()) 38 | + cafile, capath = _find_cafile_and_capath() 39 | + 40 | # environment vars shadow paths 41 | - cafile = os.environ.get(parts[0], parts[1]) 42 | - capath = os.environ.get(parts[2], parts[3]) 43 | + cafile = os.environ.get(parts[0], cafile) 44 | + capath = os.environ.get(parts[2], capath) 45 | 46 | - return DefaultVerifyPaths(cafile if os.path.isfile(cafile) else None, 47 | - capath if os.path.isdir(capath) else None, 48 | + # overwrite what we get from bundled openssl since it's useless 49 | + parts[1] = None 50 | + parts[3] = None 51 | + 52 | + return DefaultVerifyPaths(cafile if os.path.isfile(cafile or '') else None, 53 | + capath if os.path.isdir(capath or '') else None, 54 | *parts) 55 | 56 | 57 | @@ -432,7 +458,12 @@ 58 | if sys.platform == "win32": 59 | for storename in self._windows_cert_stores: 60 | self._load_windows_store_certs(storename, purpose) 61 | - self.set_default_verify_paths() 62 | + 63 | + if not os.environ.get('SSL_CERT_FILE') and not os.environ.get('SSL_CERT_DIR'): 64 | + locations = _find_cafile_and_capath() 65 | + self.load_verify_locations(*locations) 66 | + else: 67 | + self.set_default_verify_paths() 68 | 69 | 70 | def create_default_context(purpose=Purpose.SERVER_AUTH, *, cafile=None, 71 | -------------------------------------------------------------------------------- /make_portable: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | bundle = ['sqlite3', 'ssl', 'crypto', 'ffi', 'expat', 'tcl', 'tk', 'gdbm', 'lzma', 'ncursesw', 'panelw', 'tinfow'] 4 | 5 | from os import chdir, mkdir, symlink 6 | from os.path import dirname, relpath, join, samefile, exists, basename, realpath 7 | from shutil import copy2, copytree 8 | from sys import argv 9 | from glob import glob 10 | from subprocess import check_output, check_call 11 | 12 | 13 | def get_deps(binary): 14 | deps = {} 15 | output = check_output(['ldd', binary]) 16 | for line in output.splitlines(): 17 | if '=>' not in line: 18 | continue 19 | line = line.strip() 20 | needed, path = line.split(' => ') 21 | if path == 'not found': 22 | print('Broken dependency in ' + binary) 23 | path = path.split(' ')[0] 24 | path = realpath(path) 25 | if not path: 26 | continue 27 | 28 | if needed[3:].split('.', 1)[0] not in bundle: 29 | continue 30 | 31 | deps[needed] = path 32 | deps.update(get_deps(path)) 33 | 34 | return deps 35 | 36 | 37 | def gather_deps(binaries): 38 | deps = {} 39 | for binary in binaries: 40 | deps.update(get_deps(binary)) 41 | 42 | return deps 43 | 44 | 45 | def copy_deps(deps): 46 | copied = {} 47 | 48 | for needed, path in deps.items(): 49 | bname = basename(path) 50 | 51 | copy2(path, 'lib/' + bname) 52 | copied[path] = 'lib/' + bname 53 | 54 | if not exists('lib/' + needed): 55 | symlink(bname, 'lib/' + needed) 56 | 57 | return copied 58 | 59 | 60 | def rpath_binaries(binaries): 61 | rpaths = {} 62 | 63 | for binary in binaries: 64 | rpath = join('$ORIGIN', relpath('lib', dirname(binary))) 65 | check_call(['patchelf', '--set-rpath', rpath, binary]) 66 | 67 | rpaths[binary] = rpath 68 | 69 | return rpaths 70 | 71 | 72 | def strip(binaries): 73 | for binary in binaries: 74 | check_call(['chmod', 'a+w', binary]) 75 | check_call(['strip', binary]) 76 | check_call(['chmod', 'a-w', binary]) 77 | 78 | 79 | def main(): 80 | binaries = glob('bin/libpypy*.so') 81 | binaries.extend(glob('lib_pypy/*_cffi.pypy*.so')) 82 | binaries.extend(glob('lib_pypy/_pypy_openssl*.so')) 83 | binaries.extend(glob('lib_pypy/_tkinter/*_cffi.pypy*.so')) 84 | 85 | deps = gather_deps(binaries) 86 | 87 | copied = copy_deps(deps) 88 | 89 | for path, item in copied.items(): 90 | print('Copied {0} to {1}'.format(path, item)) 91 | 92 | binaries.extend(copied.values()) 93 | 94 | rpaths = rpath_binaries(binaries) 95 | for binary, rpath in rpaths.items(): 96 | print('Set RPATH of {0} to {1}'.format(binary, rpath)) 97 | 98 | strip(copied.values()) 99 | 100 | check_call('cp -Lr /opt/prefix/include/* include', shell=True) 101 | 102 | return deps 103 | 104 | 105 | if __name__ == '__main__': 106 | chdir(argv[1]) 107 | 108 | try: 109 | mkdir('lib') 110 | except OSError: 111 | pass 112 | 113 | main() 114 | 115 | # tcl/tk library 116 | copytree('/opt/prefix/lib/tcl8.6', 'lib/tcl') 117 | copytree('/opt/prefix/lib/tk8.6', 'lib/tk') 118 | check_call(['patch', 'lib_pypy/_tkinter/app.py', '/src/_tkinter_app.py.patch']) 119 | if exists('lib-python/3'): 120 | check_call(['patch', 'lib-python/3/subprocess.py', '/src/subprocess3.py.patch']) 121 | check_call(['patch', 'lib-python/3/distutils/sysconfig_pypy.py', '/src/sysconfig_pypy3.py.patch']) 122 | check_call(['patch', 'lib-python/3/ssl.py', '/src/ssl3.py.patch']) 123 | check_call('cat /src/socket.append.py >> lib-python/3/socket.py', shell=True) 124 | else: 125 | check_call(['patch', 'lib-python/2.7/ssl.py', '/src/ssl.py.patch']) 126 | check_call(['patch', 'lib-python/2.7/subprocess.py', '/src/subprocess.py.patch']) 127 | check_call(['patch', 'lib-python/2.7/distutils/sysconfig_pypy.py', '/src/sysconfig_pypy.py.patch']) 128 | check_call('cat /src/socket.append.py >> lib-python/2.7/socket.py', shell=True) 129 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ==================================== 2 | Portable PyPy distribution for Linux 3 | ==================================== 4 | 5 | Note: 6 | `As of PyPy 7.3.0 `_ 7 | the general direction and some patches from Portable PyPy were 8 | adapted/incorporated into upstream. For 7.3.0 and newer just go to official PyPy 9 | downloads page http://pypy.org/download.html and grab Linux x86-64 binary (64bit, built 10 | on CentOS6). 11 | 12 | This repository contains efforts to build 64 bit 13 | x86 `PyPy `_ binaries for various Linux distributions. The idea 14 | is that you just download an archive, uncompress it and run 15 | it instantly without installing any extra libraries or tweaking 16 | your OS. 17 | Currently they are known to work across various DEB and RPM based 18 | distributions including RHEL/Centos 6 and later, Fedora, SuSE Linux, Ubuntu and Debian stable. 19 | PyPy binaries should run on any distribution that includes glibc 2.17. 20 | 21 | 22 | Latest Python 3.6 release 23 | ========================= 24 | 25 | `PyPy3.6 7.2 x86_64 `_:: 26 | 27 | md5: f5806dbee63e64bf51b6d8453183f133 28 | sha1: fd675cc1d795f19893ed1d026a34307e0b6b0be0 29 | sha256: 59099546b4dee56edcde2c9ff706687e35bb2aa94354cd56daa78aca036bd3d8 30 | 31 | Latest Python 2.7 release 32 | ========================= 33 | 34 | `PyPy 7.2 x86_64 `_:: 35 | 36 | md5: cc8c7fb3553727476b204d1cd00eaef5 37 | sha1: 21101a1ab2a8659f699ea60613cc867e7292f55d 38 | sha256: a4f301e7629aafe4691ed1c3e9a39cf2158d86524f6ce584e5b850303e77ad81 39 | 40 | 41 | All older downloads (pre 7.2) can be found `here `_. The original mercurial repository was archived `here `_. 42 | 43 | Using virtualenv 44 | ================ 45 | 46 | For your convenience this build also includes packaged virtualenv so you 47 | don't have to install one if you haven't done it yet:: 48 | 49 | portable-pypy/bin/virtualenv-pypy my-environment 50 | 51 | In this case you don't have to add ``-p`` switch as it defaults to ``pypy`` binary 52 | located in the build. 53 | 54 | Stock virtualenv didn't work with portable binaries prior to version 2.3 that included RPATH 55 | entries in ``pypy`` binary. For these versions it's obligatory to use 56 | ``virtualenv-pypy`` that fixes this problem. 57 | 58 | Included software 59 | ================= 60 | 61 | Besides PyPy there is OpenSSL, SQLite3, libffi, expat, TCL/TK and virtualenv packaged 62 | in these builds. 63 | 64 | A word about OpenSSL 65 | ==================== 66 | 67 | This software bundles OpenSSL. Each build has a version of OpenSSL that was most recent and stable at the time of packaging this software. This is done because OpenSSL versions used across distrubtions in last 10 years greately vary and they are not compatible in ABI nor API way. This also means that if there is a major security issue with OpenSSL updating your system OpenSSL will not solve it for Portable PyPy. If you are looking for tight integration with your distribution you should probably wait until your distribution vendor packages version of PyPy you want to use or you can notify me and wait for a new build. 68 | 69 | The `ssl` module will try to locate and use your system certificate store. Namely it will look for a `/etc/pki/tls/certs/ca-bundle.crt` file (RHEL derived systems) and then look for a `/etc/ssl/certs` directory (Debian dervied systems). Finally it will fallback to bundled Mozilla trust stores extraced from `certifi` project. If you don't like this behavior or your system trust store is located somewhere else you can use `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables to point it somewhere else. 70 | 71 | How it is done 72 | ============== 73 | 74 | Binaries are built with a CentOS 6 base image with help of `docker `_. 75 | That ensures that they are built against version of GLIBC that is reasonably 76 | old not to cause problems with symbol versioning. 77 | All the dependencies are also built inside chroot from latest stable tarballs. They are packed together with PyPy 78 | into one distribution and `RPATH `_ 79 | entries are inserted into them (this ensures that they can be found relatively to each other). 80 | 81 | If you want to build it yourself checkout instructions inside `BUILD.rst`. 82 | --------------------------------------------------------------------------------