f756cfc
Name:           pypy
f756cfc
Version:        1.4.1
00e57e7
Release:        4%{?dist}
f756cfc
Summary:        Python implementation with a Just-In-Time compiler
f756cfc
f756cfc
Group:          Development/Languages
f756cfc
# LGPL and another free license we'd need to ask spot about are present in some
f756cfc
# java jars that we're not building with atm (in fact, we're deleting them
f756cfc
# before building).  If we restore those we'll have to work out the new
f756cfc
# licensing terms
f756cfc
License:        MIT and Python and UCD
f756cfc
URL:            http://pypy.org/
f756cfc
BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
f756cfc
f756cfc
# High-level configuration of the build:
f756cfc
f756cfc
# PyPy consists of an implementation of an interpreter (with JIT compilation)
f756cfc
# for the full Python language  written in a high-level language, leaving many
f756cfc
# of the implementation details as "pluggable" policies.
f756cfc
#
f756cfc
# The implementation language is then compiled down to .c code, from which we
f756cfc
# obtain a binary.
f756cfc
#
f756cfc
# This allows us to build a near-arbitrary collection of different
f756cfc
# implementations of Python with differing tradeoffs
f756cfc
#
f756cfc
# (As it happens, the implementation language is itself Python, albeit a
f756cfc
# restricted subset "RPython", chosen to making it amenable to being compiled.
f756cfc
# The result implements the full Python language though)
f756cfc
f756cfc
# We could build many different implementations of Python.
f756cfc
# For now, let's focus on the implementation that appears to be receiving the
f756cfc
# most attention upstream: the JIT-enabled build, with all standard
f756cfc
# optimizations
f756cfc
f756cfc
# Building a configuration can take significant time:
f756cfc
f756cfc
# A build of pypy (with jit) on i686 took 77 mins:
f756cfc
#  [Timer] Timings:
f756cfc
#  [Timer] annotate                       ---  583.3 s
f756cfc
#  [Timer] rtype_lltype                   ---  760.9 s
f756cfc
#  [Timer] pyjitpl_lltype                 ---  567.3 s
f756cfc
#  [Timer] backendopt_lltype              ---  375.6 s
f756cfc
#  [Timer] stackcheckinsertion_lltype     ---   54.1 s
f756cfc
#  [Timer] database_c                     ---  852.2 s
f756cfc
#  [Timer] source_c                       --- 1007.3 s
f756cfc
#  [Timer] compile_c                      ---  419.9 s
f756cfc
#  [Timer] ===========================================
f756cfc
#  [Timer] Total:                         --- 4620.5 s
f756cfc
#
f756cfc
# A build of pypy (nojit) on x86_64 took about an hour:
f756cfc
#  [Timer] Timings:
f756cfc
#  [Timer] annotate                       ---  537.5 s
f756cfc
#  [Timer] rtype_lltype                   ---  667.3 s
f756cfc
#  [Timer] backendopt_lltype              ---  385.4 s
f756cfc
#  [Timer] stackcheckinsertion_lltype     ---   42.5 s
f756cfc
#  [Timer] database_c                     ---  625.3 s
f756cfc
#  [Timer] source_c                       --- 1040.2 s
f756cfc
#  [Timer] compile_c                      ---  273.9 s
f756cfc
#  [Timer] ===========================================
f756cfc
#  [Timer] Total:                         --- 3572.0 s
f756cfc
#
f756cfc
#
f756cfc
# A build of pypy-stackless on i686 took about 87 mins:
f756cfc
#  [Timer] Timings:
f756cfc
#  [Timer] annotate                       ---  584.2 s
f756cfc
#  [Timer] rtype_lltype                   ---  777.3 s
f756cfc
#  [Timer] backendopt_lltype              ---  365.9 s
f756cfc
#  [Timer] stackcheckinsertion_lltype     ---   39.3 s
f756cfc
#  [Timer] database_c                     --- 1089.6 s
f756cfc
#  [Timer] source_c                       --- 1868.6 s
f756cfc
#  [Timer] compile_c                      ---  490.4 s
f756cfc
#  [Timer] ===========================================
f756cfc
#  [Timer] Total:                         --- 5215.3 s
f756cfc
f756cfc
f756cfc
# Should we build a "pypy" binary? (with jit)
f756cfc
# pypy-1.4/pypy/jit/backend/detect_cpu.py:getcpuclassname currently supports the
f756cfc
# following options:
f756cfc
#  'i386', 'x86'
f756cfc
#  'x86-without-sse2':
f756cfc
#  'x86_64'
f756cfc
#  'cli'
f756cfc
#  'llvm'
f756cfc
%ifarch %{ix86} x86_64
f756cfc
# FIXME: is there a better way of expressing "intel" here?
f756cfc
%global with_jit 1
f756cfc
%else
f756cfc
%global with_jit 0
f756cfc
%endif
f756cfc
f756cfc
# Should we build a "pypy-stackless" binary?
f756cfc
%global with_stackless 0
f756cfc
f756cfc
f756cfc
# Easy way to enable/disable verbose logging:
f756cfc
%global verbose_logs 0
f756cfc
f756cfc
%global pypyprefix %{_libdir}/pypy-%{version}
f756cfc
%global pylibver 2.5.2
f756cfc
f756cfc
# We refer to this subdir of the source tree in a few places during the build:
f756cfc
%global goal_dir pypy/translator/goal
f756cfc
f756cfc
f756cfc
# Turn off the brp-python-bytecompile postprocessing script
f756cfc
# We manually invoke it later on, using the freshly built pypy binary
f756cfc
%global __os_install_post \
f756cfc
  %(echo '%{__os_install_post}' | sed -e 's!/usr/lib[^[:space:]]*/brp-python-bytecompile[[:space:]].*$!!g')
f756cfc
f756cfc
# Source and patches:
f756cfc
Source0:        http://pypy.org/download/pypy-%{version}-src.tar.bz2
f756cfc
f756cfc
# Edit a translator file for linux in order to configure our cflags and dynamic libffi
f756cfc
Patch0:         pypy-1.4-config.patch
f756cfc
f756cfc
# By default, if built at a tty, the translation process renders a Mandelbrot
f756cfc
# set to indicate progress.
f756cfc
# This obscures useful messages, and may waste CPU cycles, so suppress it, and
f756cfc
# merely render dots:
f756cfc
Patch1:         pypy-1.2-suppress-mandelbrot-set-during-tty-build.patch
f756cfc
f756cfc
# test_commmands fails on SELinux systems due to a change in the output
f756cfc
# of "ls" (http://bugs.python.org/issue7108)
f756cfc
Patch2: fix-test_commands-expected-ls-output-issue7108.patch
f756cfc
f756cfc
# When locating the pypy standard libraries, look first within
f756cfc
# LIBRARY_INSTALLATION_PATH.
f756cfc
# We convert this from being a non-existant variable into a string literal
f756cfc
# with the value of "pypyprefix" in the "prep" phase below.
f756cfc
#
f756cfc
# We still use the scanning relative to the binary location when invoking a
f756cfc
# pypy binary during the build (e.g. during "check")
f756cfc
#
f756cfc
# Sent upstream (with caveats) as:
f756cfc
#   https://codespeak.net/issue/pypy-dev/issue614
f756cfc
Patch3: pypy-1.4.1-add-LIBRARY_INSTALLATION_PATH.patch
f756cfc
00e57e7
# Try to improve the readability of the generated .c code, by adding in the
00e57e7
# RPython source as comments where possible.
00e57e7
# A version of this was sent upstream as:
00e57e7
#  http://codespeak.net/pipermail/pypy-dev/2010q4/006532.html
00e57e7
# TODO: get this into the upstream bug tracker, and finish inlining
00e57e7
# support (rhbz#666963)
00e57e7
Patch4: pypy-1.4.1-more-readable-c-code.patch
00e57e7
00e57e7
f756cfc
# Build-time requirements:
f756cfc
00e57e7
# pypy's can be rebuilt using itself, rather than with CPython; doing so
00e57e7
# halves the build time.
00e57e7
#
00e57e7
# Turn it off with this boolean, to revert back to rebuilding using CPython
00e57e7
# and avoid a cycle in the build-time dependency graph:
00e57e7
#
00e57e7
%global use_self_when_building 1
00e57e7
%if 0%{use_self_when_building}
00e57e7
BuildRequires: pypy
00e57e7
%global bootstrap_python_interp pypy
00e57e7
%else
00e57e7
BuildRequires: python-devel
00e57e7
%global bootstrap_python_interp python
00e57e7
%endif
00e57e7
00e57e7
f756cfc
f756cfc
# FIXME: I'm seeing errors like this in the logs:
f756cfc
#   [translation:WARNING] The module '_rawffi' is disabled
f756cfc
#   [translation:WARNING] because importing pypy.rlib.libffi raised ImportError
f756cfc
#   [translation:WARNING] 'libffi.a' not found in ['/usr/lib/libffi', '/usr/lib']
f756cfc
# Presumably we need to fix things to support dynamically-linked libffi
f756cfc
BuildRequires:  libffi-devel
f756cfc
f756cfc
BuildRequires:  zlib-devel
f756cfc
BuildRequires:  bzip2-devel
f756cfc
BuildRequires:  ncurses-devel
f756cfc
BuildRequires:  expat-devel
f756cfc
BuildRequires:  openssl-devel
f756cfc
BuildRequires:  valgrind-devel
f756cfc
f756cfc
# Used by the selftests, though not by the build:
f756cfc
BuildRequires:  gc-devel
f756cfc
f756cfc
BuildRequires:  /usr/bin/execstack
f756cfc
f756cfc
# pypy is bundling these so we delete them in %%prep.  I don't think they are
f756cfc
# needed unless we build pypy targetted at running on the jvm.
f756cfc
#BuildRequires:  jna
f756cfc
#BuildRequires: jasmin  # Not yet in Fedora
f756cfc
f756cfc
f756cfc
# Metadata for the core package (the JIT build):
f756cfc
Requires: pypy-libs = %{version}-%{release}
f756cfc
f756cfc
%description
f756cfc
PyPy's implementation of Python, featuring a Just-In-Time compiler, and various
f756cfc
optimized implementations of the standard types (strings, dictionaries, etc)
f756cfc
f756cfc
f756cfc
%package libs
f756cfc
Group:    Development/Languages
f756cfc
Summary:  Run-time libraries used by PyPy implementations of Python
f756cfc
%description libs
f756cfc
Libraries required by the various PyPy implementations of Python.
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
%package stackless
f756cfc
Group:    Development/Languages
f756cfc
Summary:  Stackless Python interpreter built using PyPy
f756cfc
Requires: pypy-libs = %{version}-%{release}
f756cfc
%description stackless
f756cfc
Build of PyPy with support for micro-threads for massive concurrency
f756cfc
%endif
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
%package stackless
f756cfc
Group:    Development/Languages
f756cfc
Summary:  Stackless Python interpreter built using PyPy
f756cfc
Requires: pypy-libs = %{version}-%{release}
f756cfc
%description stackless
f756cfc
Build of PyPy with support for micro-threads for massive concurrency
f756cfc
%endif
f756cfc
f756cfc
f756cfc
%prep
f756cfc
%setup -q -n pypy-%{version}-src
f756cfc
%patch0 -p1 -b .configure-fedora
f756cfc
%patch1 -p1 -b .suppress-mandelbrot-set-during-tty-build
f756cfc
f756cfc
pushd lib-python/%{pylibver}
f756cfc
%patch2 -p0
f756cfc
popd
f756cfc
f756cfc
# Look for the pypy libraries within LIBRARY_INSTALLATION_PATH first:
f756cfc
%patch3 -p1
f756cfc
# Fixup LIBRARY_INSTALLATION_PATH to be a string literal containing our value
f756cfc
# for "pypyprefix":
f756cfc
sed -i \
f756cfc
  -e 's|LIBRARY_INSTALLATION_PATH|"%{pypyprefix}"|' \
f756cfc
  pypy/translator/goal/app_main.py
f756cfc
00e57e7
%patch4 -p1 -b .more-readable-c-code
00e57e7
f756cfc
f756cfc
# Replace /usr/local/bin/python shebangs with /usr/bin/python:
f756cfc
find -name "*.py" -exec \
f756cfc
  sed \
f756cfc
    -i -e "s|/usr/local/bin/python|/usr/bin/python|" \
f756cfc
    "{}" \
f756cfc
    \;
f756cfc
f756cfc
find . -name '*.jar' -exec rm \{\} \;
f756cfc
f756cfc
# Remove stray ".svn" directories present within the 1.4.1 tarball
f756cfc
# (reported as https://codespeak.net/issue/pypy-dev/issue612 )
f756cfc
find . -path '*/.svn*' -delete
f756cfc
f756cfc
# Remove DOS batch files:
f756cfc
find -name "*.bat"|xargs rm -f
f756cfc
f756cfc
# The "demo" directory gets auto-installed by virture of being listed in %doc
f756cfc
# Remove shebang lines from demo .py files, and remove executability from them:
f756cfc
for f in demo/bpnn.py ; do
f756cfc
   # Detect shebang lines && remove them:
f756cfc
   sed -e '/^#!/Q 0' -e 'Q 1' $f \
f756cfc
      && sed -i '1d' $f
f756cfc
   chmod a-x $f
f756cfc
done
f756cfc
f756cfc
%build
f756cfc
f756cfc
BuildPyPy() {
f756cfc
  ExeName=$1
f756cfc
  Options=$2
f756cfc
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "STARTING BUILD OF: $ExeName"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
f756cfc
  pushd %{goal_dir}
f756cfc
f756cfc
  # The build involves invoking a python script, passing in particular
f756cfc
  # arguments, environment variables, etc.
f756cfc
  # Some notes on those follow:
f756cfc
f756cfc
  # The generated binary embeds copies of the values of all environment
f756cfc
  # variables.  We need to unset "RPM_BUILD_ROOT" to avoid a fatal error from
f756cfc
  #  /usr/lib/rpm/check-buildroot
f756cfc
  # during the postprocessing of the rpmbuild, complaining about this
f756cfc
  # reference to the buildroot
f756cfc
f756cfc
f756cfc
  # By default, pypy's autogenerated C code is placed in
f756cfc
  #    /tmp/usession-N
f756cfc
  #  
f756cfc
  # and it appears that this stops rpm from extracting the source code to the
f756cfc
  # debuginfo package
f756cfc
  #
f756cfc
  # The logic in pypy-1.4/pypy/tool/udir.py indicates that it is generated in:
f756cfc
  #    $PYPY_USESSION_DIR/usession-$PYPY_USESSION_BASENAME-N    
f756cfc
  # and so we set PYPY_USESSION_DIR so that this tempdir is within the build
f756cfc
  # location, and set $PYPY_USESSION_BASENAME so that the tempdir is unique
f756cfc
  # for each invocation of BuildPyPy
f756cfc
f756cfc
  # Compilation flags for C code:
f756cfc
  #   pypy-1.4/pypy/translator/c/genc.py:gen_makefile
f756cfc
  # assembles a Makefile within
f756cfc
  #   THE_UDIR/testing_1/Makefile
f756cfc
  # calling out to platform.gen_makefile
f756cfc
  # For us, that's
f756cfc
  #   pypy-1.4/pypy/translator/platform/linux.py: class BaseLinux(BasePosix):
f756cfc
  # which by default has:
f756cfc
  #   CFLAGS = ['-O3', '-pthread', '-fomit-frame-pointer',
f756cfc
  #             '-Wall', '-Wno-unused']
f756cfc
  # plus all substrings from CFLAGS in the environment.
f756cfc
  # This is used to generate a value for CFLAGS that's written into the Makefile
f756cfc
f756cfc
  # https://bugzilla.redhat.com/show_bug.cgi?id=588941#c18
f756cfc
  # The generated Makefile compiles the .c files into assembler (.s), rather
f756cfc
  # than direct to .o  It then post-processes this assembler to locate
f756cfc
  # garbage-collection roots (building .lbl.s and .gcmap files, and a
f756cfc
  # "gcmaptable.s").  (The modified .lbl.s files have extra code injected
f756cfc
  # within them).
f756cfc
  # Unfortunately, the code to do this:
f756cfc
  #   pypy-1.4/pypy/translator/c/gcc/trackgcroot.py
f756cfc
  # doesn't interract well with the results of using our standard build flags.
f756cfc
  # For now, filter our CFLAGS of everything that could be conflicting with
f756cfc
  # pypy.  Need to check these and reenable ones that are okay later.
00e57e7
  # Filed as https://bugzilla.redhat.com/show_bug.cgi?id=666966
f756cfc
  export CFLAGS=$(echo "$RPM_OPT_FLAGS" | sed -e 's/-Wp,-D_FORTIFY_SOURCE=2//' -e 's/-fexceptions//' -e 's/-fstack-protector//' -e 's/--param=ssp-buffer-size=4//' -e 's/-O2//' -e 's/-fasynchronous-unwind-tables//' -e 's/-march=i686//' -e 's/-mtune=atom//')
f756cfc
f756cfc
  # If we're already built the JIT-enabled "pypy", then use it for subsequent
f756cfc
  # builds (of other configurations):
f756cfc
  if test -x './pypy' ; then
f756cfc
    INTERP='./pypy'
f756cfc
  else
00e57e7
    # First pypy build within this rpm build?
00e57e7
    # Fall back to using the bootstrap python interpreter, which might be a
00e57e7
    # system copy of pypy from an earlier rpm, or be cpython's /usr/bin/python:
00e57e7
    INTERP='%{bootstrap_python_interp}'
f756cfc
  fi
f756cfc
f756cfc
  # Here's where we actually invoke the build:
f756cfc
  time \
f756cfc
    RPM_BUILD_ROOT= \
f756cfc
    PYPY_USESSION_DIR=$(pwd) \
f756cfc
    PYPY_USESSION_BASENAME=$ExeName \
f756cfc
    $INTERP translate.py \
f756cfc
%if 0%{verbose_logs}
f756cfc
    --translation-verbose \
f756cfc
%endif
f756cfc
    --cflags="$CFLAGS" \
f756cfc
    --batch \
f756cfc
    --output=$ExeName \
f756cfc
    $Options
f756cfc
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "FINISHED BUILDING: $ExeName"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
  echo "--------------------------------------------------------------"
f756cfc
f756cfc
  popd
f756cfc
}
f756cfc
f756cfc
%if 0%{with_jit}
f756cfc
BuildPyPy \
f756cfc
  pypy \
f756cfc
  "-Ojit"
f756cfc
%endif
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
BuildPyPy \
f756cfc
  pypy-stackless \
f756cfc
   "--stackless"
f756cfc
%endif
f756cfc
f756cfc
%install
f756cfc
rm -rf $RPM_BUILD_ROOT
f756cfc
f756cfc
f756cfc
# Install the various executables:
f756cfc
f756cfc
InstallPyPy() {
f756cfc
    ExeName=$1
f756cfc
f756cfc
    install -m 755 %{goal_dir}/$ExeName %{buildroot}/%{_bindir}
f756cfc
f756cfc
    # The generated machine code doesn't need an executable stack,  but
f756cfc
    # one of the assembler files (gcmaptable.s) doesn't have the necessary
f756cfc
    # metadata to inform gcc of that, and thus gcc pessimistically assumes
f756cfc
    # that the built binary does need an executable stack.
f756cfc
    #
f756cfc
    # Reported upstream as: https://codespeak.net/issue/pypy-dev/issue610
f756cfc
    #
f756cfc
    # I tried various approaches involving fixing the build, but the simplest
f756cfc
    # approach is to postprocess the ELF file:
f756cfc
    execstack --clear-execstack %{buildroot}/%{_bindir}/$ExeName
f756cfc
}
f756cfc
f756cfc
mkdir -p %{buildroot}/%{_bindir}
f756cfc
f756cfc
%if 0%{with_jit}
f756cfc
InstallPyPy pypy
f756cfc
%endif
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
InstallPyPy pypy-stackless
f756cfc
%endif
f756cfc
f756cfc
f756cfc
# Install the various support libraries as described at:
f756cfc
#   http://codespeak.net/pypy/dist/pypy/doc/getting-started-python.html#installation
f756cfc
# which refers to a "PREFIX" found relative to the location of the binary.
f756cfc
# Given that the pypy binaries will be in /usr/bin, PREFIX can be
f756cfc
# "../share/pypy-1.2" relative to that directory, i.e. /usr/share/pypy-1.2
f756cfc
# 
f756cfc
# Running "strace" on a built binary indicates that it searches within
f756cfc
#   PREFIX/lib-python/modified-2.5.2
f756cfc
# not
f756cfc
#   PREFIX/lib-python/modified.2.5.2
f756cfc
# as given on the above page, i.e. it uses '-' not '.'
f756cfc
f756cfc
mkdir -p %{buildroot}/%{pypyprefix}
f756cfc
cp -a lib-python %{buildroot}/%{pypyprefix}
f756cfc
f756cfc
cp -a lib_pypy %{buildroot}/%{pypyprefix}
f756cfc
f756cfc
# Remove a text file that documents which selftests fail on Win32:
f756cfc
rm %{buildroot}/%{pypyprefix}/lib-python/win32-failures.txt
f756cfc
f756cfc
# Remove shebang lines from .py files that aren't executable, and
f756cfc
# remove executability from .py files that don't have a shebang line:
f756cfc
find \
f756cfc
  %{buildroot}                                                           \
f756cfc
  -name "*.py"                                                           \
f756cfc
    \(                                                                   \
f756cfc
       \( \! -perm /u+x,g+x,o+x -exec sed -e '/^#!/Q 0' -e 'Q 1' {} \;   \
f756cfc
             -print -exec sed -i '1d' {} \;                              \
f756cfc
          \)                                                             \
f756cfc
       -o                                                                \
f756cfc
       \(                                                                \
f756cfc
             -perm /u+x,g+x,o+x ! -exec grep -m 1 -q '^#!' {} \;         \
f756cfc
             -exec chmod a-x {} \;                                       \
f756cfc
        \)                                                               \
f756cfc
    \)
f756cfc
f756cfc
mkdir -p %{buildroot}/%{pypyprefix}/site-packages
f756cfc
f756cfc
f756cfc
# pypy uses .pyc files by default (--objspace-usepycfiles), but has a slightly
f756cfc
# different bytecode format to CPython.  It doesn't use .pyo files: the -O flag
f756cfc
# is treated as a "dummy optimization flag for compatibility with C Python"
f756cfc
#
f756cfc
# pypy-1.4/pypy/module/imp/importing.py has this comment:
f756cfc
    # XXX picking a magic number is a mess.  So far it works because we
f756cfc
    # have only two extra opcodes, which bump the magic number by +1 and
f756cfc
    # +2 respectively, and CPython leaves a gap of 10 when it increases
f756cfc
    # its own magic number.  To avoid assigning exactly the same numbers
f756cfc
    # as CPython we always add a +2.  We'll have to think again when we
f756cfc
    # get at the fourth new opcode :-(
f756cfc
    #
f756cfc
    #  * CALL_LIKELY_BUILTIN    +1
f756cfc
    #  * CALL_METHOD            +2
f756cfc
    #
f756cfc
    # In other words:
f756cfc
    #
f756cfc
    #     default_magic        -- used by CPython without the -U option
f756cfc
    #     default_magic + 1    -- used by CPython with the -U option
f756cfc
    #     default_magic + 2    -- used by PyPy without any extra opcode
f756cfc
    #     ...
f756cfc
    #     default_magic + 5    -- used by PyPy with both extra opcodes
f756cfc
#
f756cfc
f756cfc
# pypy-1.4/pypy/interpreter/pycode.py has:
f756cfc
#
f756cfc
#  default_magic = (62141+2) | 0x0a0d0000                  # this PyPy's magic
f756cfc
#                                                          # (62131=CPython 2.5.1)
f756cfc
# giving a value for "default_magic" for PyPy of 0xa0df2bf.
f756cfc
# Note that this corresponds to the "default_magic + 2" from the comment above
f756cfc
f756cfc
# In my builds:
f756cfc
#   $ ./pypy --info | grep objspace.opcodes
f756cfc
#                objspace.opcodes.CALL_LIKELY_BUILTIN: False
f756cfc
#                        objspace.opcodes.CALL_METHOD: True
f756cfc
# so I'd expect the magic number to be:
f756cfc
#    0x0a0df2bf + 2 (the flag for CALL_METHOD)
f756cfc
# giving
f756cfc
#    0x0a0df2c1
f756cfc
#
f756cfc
# I'm seeing
f756cfc
#   c1 f2 0d 0a
f756cfc
# as the first four bytes of the .pyc files, which is consistent with this.
f756cfc
f756cfc
f756cfc
# Bytecompile all of the .py files we ship, using our pypy binary, giving us
f756cfc
# .pyc files for pypy.  The script actually does the work twice (passing in -O
f756cfc
# the second time) but it's simplest to reuse that script.
f756cfc
#
f756cfc
# The script has special-casing for .py files below
f756cfc
#    /usr/lib{64}/python[0-9].[0-9]
f756cfc
# but given that we're installing into a different path, the supplied "default"
f756cfc
# implementation gets used instead.
f756cfc
#
f756cfc
# Note that some of the test files deliberately contain syntax errors, so
f756cfc
# we pass 0 for the second argument ("errors_terminate"):
f756cfc
/usr/lib/rpm/brp-python-bytecompile \
f756cfc
  %{buildroot}/%{_bindir}/pypy \
f756cfc
  0
f756cfc
00e57e7
# Capture the RPython source code files from the build within the debuginfo
00e57e7
# package (rhbz#666975)
00e57e7
%global pypy_debuginfo_dir /usr/src/debug/pypy-%{version}-src
00e57e7
mkdir -p %{buildroot}%{pypy_debuginfo_dir}
00e57e7
00e57e7
# copy over everything:
00e57e7
cp -a pypy %{buildroot}%{pypy_debuginfo_dir}
00e57e7
00e57e7
# ...then delete files that aren't .py files:
00e57e7
find \
00e57e7
  %{buildroot}%{pypy_debuginfo_dir} \
00e57e7
  \( -type f                        \
00e57e7
     -a                             \
00e57e7
     \! -name "*.py"                \
00e57e7
  \)                                \
00e57e7
  -delete
00e57e7
00e57e7
# We don't need bytecode for these files; they are being included for reference
00e57e7
# purposes.
00e57e7
# There are some rpmlint warnings from these files:
00e57e7
#   non-executable-script
00e57e7
#   wrong-script-interpreter
00e57e7
#   zero-length
00e57e7
#   script-without-shebang
00e57e7
#   dangling-symlink
00e57e7
# but given that the objective is to preserve a copy of the source code, those
00e57e7
# are acceptable.
00e57e7
f756cfc
%check
f756cfc
topdir=$(pwd)
f756cfc
f756cfc
SkipTest() {
f756cfc
    # Append the given test name to TESTS_TO_SKIP
f756cfc
    TEST_NAME=$1
f756cfc
    TESTS_TO_SKIP="$TESTS_TO_SKIP $TEST_NAME"
f756cfc
}
f756cfc
f756cfc
CheckPyPy() {
f756cfc
    # We'll be exercising one of the freshly-built binaries using the
f756cfc
    # test suite from the standard library (overridden in places by pypy's
f756cfc
    # modified version)
f756cfc
    ExeName=$1
f756cfc
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "STARTING TEST OF: $ExeName"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
f756cfc
    pushd %{goal_dir}
f756cfc
f756cfc
    # Gather a list of tests to skip, due to known failures
f756cfc
    # TODO: report these failures to pypy upstream
00e57e7
    # See also rhbz#666967 and rhbz#666969
f756cfc
    TESTS_TO_SKIP=""
f756cfc
f756cfc
    # Test failures relating to missing codecs
f756cfc
    # Hopefully when pypy merges to 2.7 support we'll gain these via a
f756cfc
    # refreshed stdlib:
f756cfc
      # test_codecencodings_cn:
f756cfc
      #   all tests fail, with one of
f756cfc
      #     unknown encoding: gb18030
f756cfc
      #     unknown encoding: gb2312
f756cfc
      #     unknown encoding: gbk
f756cfc
      SkipTest test_codecencodings_cn
f756cfc
f756cfc
      # test_codecencodings_hk:
f756cfc
      #   all tests fail, with:
f756cfc
      #     unknown encoding: big5hkscs
f756cfc
      SkipTest test_codecencodings_hk
f756cfc
f756cfc
      # test_codecencodings_jp:
f756cfc
      #   all tests fail, with one of:
f756cfc
      #     unknown encoding: cp932
f756cfc
      #     unknown encoding: euc_jisx0213
f756cfc
      #     unknown encoding: euc_jp
f756cfc
      #     unknown encoding: shift_jis
f756cfc
      #     unknown encoding: shift_jisx0213
f756cfc
      SkipTest test_codecencodings_jp
f756cfc
f756cfc
      # test_codecencodings_kr:
f756cfc
      #   all tests fail, with one of:
f756cfc
      #     unknown encoding: cp949
f756cfc
      #     unknown encoding: euc_kr
f756cfc
      #     unknown encoding: johab
f756cfc
      SkipTest test_codecencodings_kr
f756cfc
f756cfc
      # test_codecencodings_tw:
f756cfc
      #    all tests fail, with:
f756cfc
      #      unknown encoding: big5
f756cfc
      SkipTest test_codecencodings_tw
f756cfc
f756cfc
      # test_multibytecodec:
f756cfc
      #   14 failures out of 15, due to:
f756cfc
      #     unknown encoding: euc-kr
f756cfc
      #     unknown encoding: gb2312
f756cfc
      #     unknown encoding: jisx0213
f756cfc
      #     unknown encoding: cp949
f756cfc
      #     unknown encoding: iso2022-jp
f756cfc
      #     unknown encoding: gb18030
f756cfc
      SkipTest test_multibytecodec
f756cfc
f756cfc
    #
f756cfc
    # Other failures:
f756cfc
    #
f756cfc
      # test_asynchat:
f756cfc
      #   seems to hang on this test, within test_line_terminator
f756cfc
      SkipTest test_asynchat
f756cfc
f756cfc
      # test_compiler:
f756cfc
      #   4 errors out of 13:
f756cfc
      #     testSourceCodeEncodingsError
f756cfc
      #     testWith
f756cfc
      #     testWithAss
f756cfc
      #     testYieldExpr
f756cfc
      SkipTest test_compiler
f756cfc
f756cfc
      # test_ctypes:
f756cfc
      #   failures=17, errors=20, out of 132 tests
f756cfc
      SkipTest test_ctypes
f756cfc
f756cfc
      # test_frozen:
f756cfc
      #   TestFailed: import __hello__ failed:No module named __hello__
f756cfc
      SkipTest test_frozen
f756cfc
f756cfc
      # test_iterlen:
f756cfc
      #   24 failures out of 25, apparently all due to TypeError
f756cfc
      SkipTest test_iterlen
f756cfc
f756cfc
      # test_parser:
f756cfc
      #   12 failures out of 15
f756cfc
      SkipTest test_parser
f756cfc
f756cfc
      # test_platform:
f756cfc
      #   Koji builds show:
f756cfc
      #    test test_platform failed -- errors occurred in test.test_platform.PlatformTest
f756cfc
      SkipTest test_platform
f756cfc
f756cfc
      # test_socket:
f756cfc
      #   testSockName can fail in Koji with:
f756cfc
      #       my_ip_addr = socket.gethostbyname(socket.gethostname())
f756cfc
      #     gaierror: (-3, 'Temporary failure in name resolution')
f756cfc
      SkipTest test_socket
f756cfc
f756cfc
      # test_sort:
f756cfc
      #   some failures
f756cfc
      SkipTest test_sort
f756cfc
f756cfc
      # test_sqlite:
f756cfc
      #   3 of the sqlite3.test.dbapi.ExtensionTests raise:
f756cfc
      #     ProgrammingError: Incomplete statement ''
f756cfc
      SkipTest test_sqlite
f756cfc
f756cfc
      # test_traceback:
f756cfc
      #   works when run standalone; failures seen when run as part of a suite
f756cfc
      SkipTest test_traceback
f756cfc
f756cfc
      # test_zlib:
f756cfc
      #   failure seen in Koji, not sure of reason why:
f756cfc
      #     test test_zlib failed -- Traceback (most recent call last):
f756cfc
      #     File "/builddir/build/BUILD/pypy-1.4.1-src/lib-python/2.5.2/test/test_zlib.py", line 72, in test_baddecompressobj
f756cfc
      #       self.assertRaises(ValueError, zlib.decompressobj, 0)
f756cfc
      #     AssertionError: ValueError not raised
f756cfc
      SkipTest test_zlib
f756cfc
00e57e7
    %if 0%{use_self_when_building}
00e57e7
    # Patch 3 prioritizes the installed copy of pypy's libraries over the
00e57e7
    # build copy.
00e57e7
    # This leads to test failures of test_pep263 and test_tarfile
00e57e7
    # For now, suppress these when building using pypy itself:
00e57e7
    SkipTest test_pep263   # on-disk encoding issues
00e57e7
    SkipTest test_tarfile  # permissions issues
00e57e7
    %endif
f756cfc
f756cfc
    # Run the built binary through the selftests:
f756cfc
    time ./$ExeName -m test.regrtest -x $TESTS_TO_SKIP
f756cfc
f756cfc
    popd
f756cfc
f756cfc
    # Doublecheck pypy's own test suite, using the built pypy binary:
f756cfc
f756cfc
    # Disabled for now:
f756cfc
    #   x86_64 shows various failures inside:
f756cfc
    #     jit/backend/x86/test
f756cfc
    #   followed by a segfault inside
f756cfc
    #     jit/backend/x86/test/test_runner.py
f756cfc
    #
f756cfc
    #   i686 shows various failures inside:
f756cfc
    #     jit/backend/x86/test
f756cfc
    #   with the x86_64 failure leading to cancellation of the i686 build
f756cfc
f756cfc
    # Here's the disabled code:
f756cfc
    #    pushd pypy
f756cfc
    #    time translator/goal/$ExeName test_all.py
f756cfc
    #    popd
f756cfc
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "FINISHED TESTING: $ExeName"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
    echo "--------------------------------------------------------------"
f756cfc
}
f756cfc
f756cfc
%if 0%{with_jit}
f756cfc
CheckPyPy pypy
f756cfc
%endif
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
CheckPyPy pypy-stackless
f756cfc
%endif
f756cfc
f756cfc
f756cfc
f756cfc
%clean
f756cfc
rm -rf $RPM_BUILD_ROOT
f756cfc
f756cfc
f756cfc
%files libs
f756cfc
%defattr(-,root,root,-)
f756cfc
%doc LICENSE README demo
f756cfc
f756cfc
%dir %{pypyprefix}
f756cfc
%dir %{pypyprefix}/lib-python
f756cfc
%{pypyprefix}/lib-python/%{pylibver}/
f756cfc
%{pypyprefix}/lib-python/modified-%{pylibver}/
f756cfc
%{pypyprefix}/lib-python/conftest.py*
f756cfc
%{pypyprefix}/lib_pypy/
f756cfc
%{pypyprefix}/site-packages/
f756cfc
f756cfc
%if 0%{with_jit}
f756cfc
%files
f756cfc
%defattr(-,root,root,-)
f756cfc
%doc LICENSE README
f756cfc
%{_bindir}/pypy
f756cfc
%endif
f756cfc
f756cfc
%if 0%{with_stackless}
f756cfc
%files stackless
f756cfc
%defattr(-,root,root,-)
f756cfc
%doc LICENSE README
f756cfc
%{_bindir}/pypy-stackless
f756cfc
%endif
f756cfc
f756cfc
f756cfc
%changelog
00e57e7
* Wed Jan  5 2011 David Malcolm <dmalcolm@redhat.com> - 1.4.1-4
00e57e7
- rebuild pypy using itself, for speed, with a boolean to break this cycle in
00e57e7
the build-requirement graph (falling back to using "python-devel" aka CPython)
00e57e7
- add work-in-progress patch to try to make generated c more readable
00e57e7
(rhbz#666963)
00e57e7
- capture the RPython source code files from the build within the debuginfo
00e57e7
package (rhbz#666975)
00e57e7
f756cfc
* Wed Dec 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.4.1-3
f756cfc
- try to respect the FHS by installing libraries below libdir, rather than
f756cfc
datadir; patch app_main.py to look in this installation location first when
f756cfc
scanning for the pypy library directories.
f756cfc
- clarifications and corrections to the comments in the specfile
f756cfc
f756cfc
* Wed Dec 22 2010 David Malcolm <dmalcolm@redhat.com> - 1.4.1-2
f756cfc
- remove .svn directories
f756cfc
- disable verbose logging
f756cfc
- add a %%check section
f756cfc
- introduce %%goal_dir variable, to avoid repetition
f756cfc
- remove shebang line from demo/bpnn.py, as we're treating this as a
f756cfc
documentation file
f756cfc
- regenerate patch 2 to apply without generating a .orig file
f756cfc
f756cfc
* Tue Dec 21 2010 David Malcolm <dmalcolm@redhat.com> - 1.4.1-1
f756cfc
- 1.4.1; fixup %%setup to reflect change in toplevel directory in upstream
f756cfc
source tarball
f756cfc
- apply SELinux fix to the bundled test_commands.py (patch 2)
f756cfc
f756cfc
* Wed Dec 15 2010 David Malcolm <dmalcolm@redhat.com> - 1.4-4
f756cfc
- rename the jit build and subpackge to just "pypy", and remove the nojit and
f756cfc
sandbox builds, as upstream now seems to be focussing on the JIT build (with
f756cfc
only stackless called out in the getting-started-python docs); disable
f756cfc
stackless for now
f756cfc
- add a verbose_logs specfile boolean; leave it enabled for now (whilst fixing
f756cfc
build issues)
f756cfc
- add more comments, and update others to reflect 1.2 -> 1.4 changes
f756cfc
- re-enable debuginfo within CFLAGS ("-g")
f756cfc
- add the LICENSE and README to all subpackages
f756cfc
- ensure the built binaries don't have the "I need an executable stack" flag
f756cfc
- remove DOS batch files during %%prep (idlelib.bat)
f756cfc
- remove shebang lines from .py files that aren't executable, and remove
f756cfc
executability from .py files that don't have a shebang line (taken from
f756cfc
our python3.spec)
f756cfc
- bytecompile the .py files into .pyc files in pypy's bytecode format
f756cfc
f756cfc
* Sun Nov 28 2010 Toshio Kuratomi <toshio@fedoraproject.org> - 1.4-3
f756cfc
- BuildRequire valgrind-devel
f756cfc
- Install pypy library from the new directory
f756cfc
- Disable building with our CFLAGS for now because they are causing a build failure.
f756cfc
- Include site-packages directory
f756cfc
f756cfc
* Sat Nov 27 2010 Toshio Kuratomi <toshio@fedoraproject.org> - 1.4-2
f756cfc
- Add patch to configure the build to use our CFLAGS and link libffi
f756cfc
  dynamically
f756cfc
f756cfc
* Sat Nov 27 2010 Toshio Kuratomi <toshio@fedoraproject.org> - 1.4-1
f756cfc
- Update to 1.4
f756cfc
- Drop patch for py2.6 that's in this build
f756cfc
- Switch to building pypy with itself once pypy is built once as recommended by
f756cfc
  upstream
f756cfc
- Remove bundled, prebuilt java libraries
f756cfc
- Fix license tag
f756cfc
- Fix source url
f756cfc
- Version pypy-libs Req
f756cfc
f756cfc
* Tue May  4 2010 David Malcolm <dmalcolm@redhat.com> - 1.2-2
f756cfc
- cherrypick r72073 from upstream SVN in order to fix the build against
f756cfc
python 2.6.5 (patch 2)
f756cfc
f756cfc
* Wed Apr 28 2010 David Malcolm <dmalcolm@redhat.com> - 1.2-1
f756cfc
- initial packaging
f756cfc