diff --git a/brp-python-bytecompile b/brp-python-bytecompile index 71f4d2d..cbc5830 100644 --- a/brp-python-bytecompile +++ b/brp-python-bytecompile @@ -29,7 +29,6 @@ fi # Python < 3.4 (inc. Python 2) uses compileall module from stdlib with some hacks # When we drop support for Python 2, we'd be able to use all compileall2 features like: # - -s and -p options to manipulate with a path baked into pyc files instead of $real_libdir -# - -o 0 -o 1 to produce multiple files in one run - each with a different optimization level - instead of $options # - removed useless $depth - both compileall and compileall2 are limited by sys.getrecursionlimit() # These changes will make this script much simpler # In Python >= 3.9, compileall2 was merged back to standard library (compileall) so we can use it directly again. @@ -49,6 +48,12 @@ function python_bytecompile() # if [ "$python_version" -ge 39 ]; then + # For Python 3.9+, we compile all opt levels in one go: only + # when $options is empty. + if [ -n "$options" ]; then + return + fi + [ ! -z $exclude ] && exclude="-x '$exclude'" # -q disables verbose output # -f forces the process to overwrite existing compiled files @@ -57,7 +62,7 @@ function python_bytecompile() # -x and -e together implements the same functionality as the Filter class below # -s strips $RPM_BUILD_ROOT from the path # -p prepends the leading slash to the path to make it absolute - $python_binary -B $options -m compileall -q -f $exclude -s "$RPM_BUILD_ROOT" -p / -e "$RPM_BUILD_ROOT" "$python_libdir" + $python_binary -B -m compileall -o 0 -o 1 -q -f $exclude -s "$RPM_BUILD_ROOT" -p / --hardlink-dupes -e "$RPM_BUILD_ROOT" "$python_libdir" # # Python 3.4 and higher @@ -133,6 +138,7 @@ do fi # Generate optimized (.pyo) byte-compiled files. + # N.B. For Python 3.9+, this call does nothing python_bytecompile "-O" "$python_binary" "" "$python_libdir" "$depth" "$real_libdir" if [ $? -ne 0 -a 0$errors_terminate -ne 0 ]; then # One or more of the files had a syntax error diff --git a/macros.pybytecompile b/macros.pybytecompile index b58fff4..6c89c8b 100644 --- a/macros.pybytecompile +++ b/macros.pybytecompile @@ -34,7 +34,7 @@ py3_byte_compile () {\ py39_byte_compile () {\ python_binary="env PYTHONHASHSEED=0 %1"\ bytecode_compilation_path="%2"\ - $python_binary -s -B -m compileall -o 0 -o 1 -s $RPM_BUILD_ROOT -p / $bytecode_compilation_path \ + $python_binary -s -B -m compileall -o 0 -o 1 -s $RPM_BUILD_ROOT -p / --hardlink-dupes $bytecode_compilation_path \ }\ \ # Path to intepreter should not contain any arguments \ diff --git a/python-rpm-macros.spec b/python-rpm-macros.spec index 937ea48..e39b07f 100644 --- a/python-rpm-macros.spec +++ b/python-rpm-macros.spec @@ -47,7 +47,7 @@ elseif posix.stat('macros.python-srpm') then end } Version: %{__default_python3_version} -Release: 7%{?dist} +Release: 8%{?dist} BuildArch: noarch @@ -141,6 +141,11 @@ install -m 755 brp-* %{buildroot}%{_rpmconfigdir}/redhat/ %changelog +* Thu Sep 09 2021 Petr Viktorin - 3.10-8 +- Use --hardlink-dupes in %%py_byte_compile and brp-python-bytecompile + (for Python 3.9+) +- Resolves: rhbz#1977895 + * Fri Jul 23 2021 Fedora Release Engineering - 3.9-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild diff --git a/tests/pythontest.spec b/tests/pythontest.spec index a0f052c..182ba59 100644 --- a/tests/pythontest.spec +++ b/tests/pythontest.spec @@ -19,15 +19,35 @@ echo "print()" > %{buildroot}%{basedir}/directory/to/test/recursion/file_in_dir. %py_byte_compile %{python3} %{buildroot}%{basedir}/file.py %py_byte_compile %{python3} %{buildroot}%{basedir}/directory +# Files in sitelib are compiled automatically by brp-python-bytecompile +mkdir -p %{buildroot}%{python3_sitelib}/directory/ +echo "print()" > %{buildroot}%{python3_sitelib}/directory/file.py + %check +LOCATIONS="%{buildroot}%{basedir} %{buildroot}%{python3_sitelib}/directory/" + # Count .py and .pyc files -PY=$(find %{buildroot}%{basedir} -name "*.py" | wc -l) -PYC=$(find %{buildroot}%{basedir} -name "*.pyc" | wc -l) +PY=$(find $LOCATIONS -name "*.py" | wc -l) +PYC=$(find $LOCATIONS -name "*.pyc" | wc -l) + +# We should have 3 .py files +test $PY -eq 3 # Every .py file should be byte-compiled to two .pyc files (optimization level 0 and 1) # so we should have two times more .pyc files than .py files test $(expr $PY \* 2) -eq $PYC +# In this case the .pyc files should be identical across omtimization levels +# (they don't use docstrings and assert staements) +# So they should be hardlinked; the number of distinct inodes should match the +# number of source files. (Or be smaller, if the dupe detection is done +# across all files.) + +INODES=$(stat --format %i $(find $LOCATIONS -name "*.pyc") | sort -u | wc -l) +test $PY -ge $INODES + + %files %pycached %{basedir}/file.py %pycached %{basedir}/directory/to/test/recursion/file_in_dir.py +%pycached %{python3_sitelib}/directory/file.py