This also includes some cleanup in preparation for a PR to make the "make all" output less noisy.
https://bugs.python.org/issue45020
############################################################################
# frozen modules (including importlib)
+# FROZEN_FILES_* are auto-generated by Tools/scripts/freeze_modules.py.
+FROZEN_FILES_IN = \
+ Lib/importlib/_bootstrap.py \
+ Lib/importlib/_bootstrap_external.py \
+ Lib/zipimport.py \
+ Lib/abc.py \
+ Lib/codecs.py \
+ Lib/io.py \
+ Lib/_collections_abc.py \
+ Lib/_sitebuiltins.py \
+ Lib/genericpath.py \
+ Lib/ntpath.py \
+ Lib/posixpath.py \
+ Lib/os.py \
+ Lib/site.py \
+ Lib/stat.py \
+ Lib/__hello__.py
+# End FROZEN_FILES_IN
+FROZEN_FILES_OUT = \
+ Python/frozen_modules/importlib._bootstrap.h \
+ Python/frozen_modules/importlib._bootstrap_external.h \
+ Python/frozen_modules/zipimport.h \
+ Python/frozen_modules/abc.h \
+ Python/frozen_modules/codecs.h \
+ Python/frozen_modules/io.h \
+ Python/frozen_modules/_collections_abc.h \
+ Python/frozen_modules/_sitebuiltins.h \
+ Python/frozen_modules/genericpath.h \
+ Python/frozen_modules/ntpath.h \
+ Python/frozen_modules/posixpath.h \
+ Python/frozen_modules/os.h \
+ Python/frozen_modules/site.h \
+ Python/frozen_modules/stat.h \
+ Python/frozen_modules/__hello__.h
+# End FROZEN_FILES_OUT
+
Programs/_freeze_module.o: Programs/_freeze_module.c Makefile
Programs/_freeze_module: Programs/_freeze_module.o $(LIBRARY_OBJS_OMIT_FROZEN)
$(LINKCC) $(PY_CORE_LDFLAGS) -o $@ Programs/_freeze_module.o $(LIBRARY_OBJS_OMIT_FROZEN) $(LIBS) $(MODLIBS) $(SYSLIBS)
-Tools/scripts/freeze_modules.py: Programs/_freeze_module
-
-.PHONY: regen-frozen
-regen-frozen: Tools/scripts/freeze_modules.py $(FROZEN_FILES)
- $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/freeze_modules.py
- @echo "The Makefile was updated, you may need to re-run make."
-
# BEGIN: freezing modules
-Python/frozen_modules/importlib__bootstrap.h: Programs/_freeze_module Lib/importlib/_bootstrap.py
- Programs/_freeze_module importlib._bootstrap $(srcdir)/Lib/importlib/_bootstrap.py $(srcdir)/Python/frozen_modules/importlib__bootstrap.h
+Python/frozen_modules/importlib._bootstrap.h: Programs/_freeze_module Lib/importlib/_bootstrap.py
+ Programs/_freeze_module importlib._bootstrap $(srcdir)/Lib/importlib/_bootstrap.py $(srcdir)/Python/frozen_modules/importlib._bootstrap.h
-Python/frozen_modules/importlib__bootstrap_external.h: Programs/_freeze_module Lib/importlib/_bootstrap_external.py
- Programs/_freeze_module importlib._bootstrap_external $(srcdir)/Lib/importlib/_bootstrap_external.py $(srcdir)/Python/frozen_modules/importlib__bootstrap_external.h
+Python/frozen_modules/importlib._bootstrap_external.h: Programs/_freeze_module Lib/importlib/_bootstrap_external.py
+ Programs/_freeze_module importlib._bootstrap_external $(srcdir)/Lib/importlib/_bootstrap_external.py $(srcdir)/Python/frozen_modules/importlib._bootstrap_external.h
Python/frozen_modules/zipimport.h: Programs/_freeze_module Lib/zipimport.py
Programs/_freeze_module zipimport $(srcdir)/Lib/zipimport.py $(srcdir)/Python/frozen_modules/zipimport.h
# END: freezing modules
+Tools/scripts/freeze_modules.py: Programs/_freeze_module
+
+.PHONY: regen-frozen
+regen-frozen: Tools/scripts/freeze_modules.py $(FROZEN_FILES_IN)
+ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/freeze_modules.py
+ @echo "The Makefile was updated, you may need to re-run make."
+
# We keep this renamed target around for folks with muscle memory.
.PHONY: regen-importlib
regen-importlib: regen-frozen
Python/ceval.o: $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/ceval_gil.h \
$(srcdir)/Python/condvar.h
-# FROZEN_FILES is auto-generated by Tools/scripts/freeze_modules.py.
-FROZEN_FILES = \
- Python/frozen_modules/importlib__bootstrap.h \
- Python/frozen_modules/importlib__bootstrap_external.h \
- Python/frozen_modules/zipimport.h \
- Python/frozen_modules/abc.h \
- Python/frozen_modules/codecs.h \
- Python/frozen_modules/io.h \
- Python/frozen_modules/_collections_abc.h \
- Python/frozen_modules/_sitebuiltins.h \
- Python/frozen_modules/genericpath.h \
- Python/frozen_modules/ntpath.h \
- Python/frozen_modules/posixpath.h \
- Python/frozen_modules/os.h \
- Python/frozen_modules/site.h \
- Python/frozen_modules/stat.h \
- Python/frozen_modules/__hello__.h
-# End FROZEN_FILES
-
-Python/frozen.o: $(FROZEN_FILES)
+Python/frozen.o: $(FROZEN_FILES_OUT)
# Generate DTrace probe macros, then rename them (PYTHON_ -> PyDTrace_) to
# follow our naming conventions. dtrace(1) uses the output filename to generate
<!-- BEGIN frozen modules -->
<None Include="..\Lib\importlib\_bootstrap.py">
<ModName>importlib._bootstrap</ModName>
- <IntFile>$(IntDir)importlib__bootstrap.g.h</IntFile>
- <OutFile>$(PySourcePath)Python\frozen_modules\importlib__bootstrap.h</OutFile>
+ <IntFile>$(IntDir)importlib._bootstrap.g.h</IntFile>
+ <OutFile>$(PySourcePath)Python\frozen_modules\importlib._bootstrap.h</OutFile>
</None>
<None Include="..\Lib\importlib\_bootstrap_external.py">
<ModName>importlib._bootstrap_external</ModName>
- <IntFile>$(IntDir)importlib__bootstrap_external.g.h</IntFile>
- <OutFile>$(PySourcePath)Python\frozen_modules\importlib__bootstrap_external.h</OutFile>
+ <IntFile>$(IntDir)importlib._bootstrap_external.g.h</IntFile>
+ <OutFile>$(PySourcePath)Python\frozen_modules\importlib._bootstrap_external.h</OutFile>
</None>
<None Include="..\Lib\zipimport.py">
<ModName>zipimport</ModName>
#include "Python.h"
/* Includes for frozen modules: */
-#include "frozen_modules/importlib__bootstrap.h"
-#include "frozen_modules/importlib__bootstrap_external.h"
+#include "frozen_modules/importlib._bootstrap.h"
+#include "frozen_modules/importlib._bootstrap_external.h"
#include "frozen_modules/zipimport.h"
#include "frozen_modules/abc.h"
#include "frozen_modules/codecs.h"
import subprocess
import sys
import textwrap
+import time
-from update_file import updating_file_with_tmpfile
+from update_file import updating_file_with_tmpfile, update_file_with_tmpfile
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
except AttributeError:
raise ValueError(f'unsupported frozenid {frozenid!r}')
# We use a consistent naming convention for all frozen modules.
- frozenfile = frozenid.replace('.', '_') + '.h'
+ frozenfile = f'{frozenid}.h'
if not destdir:
return frozenfile
return os.path.join(destdir, frozenfile)
def regen_makefile(modules):
+ pyfiles = []
frozenfiles = []
rules = ['']
for src in _iter_sources(modules):
frozenfiles.append(f'\t\t{header} \\')
pyfile = relpath_for_posix_display(src.pyfile, ROOT_DIR)
- # Note that we freeze the module to the target .h file
- # instead of going through an intermediate file like we used to.
- rules.append(f'{header}: Programs/_freeze_module {pyfile}')
- rules.append(
- (f'\tPrograms/_freeze_module {src.frozenid} '
- f'$(srcdir)/{pyfile} $(srcdir)/{header}'))
- rules.append('')
-
+ pyfiles.append(f'\t\t{pyfile} \\')
+
+ freeze = (f'Programs/_freeze_module {src.frozenid} '
+ f'$(srcdir)/{pyfile} $(srcdir)/{header}')
+ rules.extend([
+ f'{header}: Programs/_freeze_module {pyfile}',
+ f'\t{freeze}',
+ '',
+ ])
+ pyfiles[-1] = pyfiles[-1].rstrip(" \\")
frozenfiles[-1] = frozenfiles[-1].rstrip(" \\")
print(f'# Updating {os.path.relpath(MAKEFILE)}')
lines = infile.readlines()
lines = replace_block(
lines,
- "FROZEN_FILES =",
- "# End FROZEN_FILES",
+ "FROZEN_FILES_IN =",
+ "# End FROZEN_FILES_IN",
+ pyfiles,
+ MAKEFILE,
+ )
+ lines = replace_block(
+ lines,
+ "FROZEN_FILES_OUT =",
+ "# End FROZEN_FILES_OUT",
frozenfiles,
MAKEFILE,
)
def freeze_module(modname, pyfile=None, destdir=MODULES_DIR):
"""Generate the frozen module .h file for the given module."""
+ tmpsuffix = f'.{int(time.time())}'
for modname, pyfile, ispkg in resolve_modules(modname, pyfile):
frozenfile = resolve_frozen_file(modname, destdir)
- _freeze_module(modname, pyfile, frozenfile)
+ _freeze_module(modname, pyfile, frozenfile, tmpsuffix)
-def _freeze_module(frozenid, pyfile, frozenfile):
- tmpfile = frozenfile + '.new'
+def _freeze_module(frozenid, pyfile, frozenfile, tmpsuffix):
+ tmpfile = f'{frozenfile}.{int(time.time())}'
+ print(tmpfile)
argv = [TOOL, frozenid, pyfile, tmpfile]
print('#', ' '.join(os.path.relpath(a) for a in argv), flush=True)
sys.exit(f'ERROR: missing {TOOL}; you need to run "make regen-frozen"')
raise # re-raise
- os.replace(tmpfile, frozenfile)
+ update_file_with_tmpfile(frozenfile, tmpfile, create=True)
#######################################
# Expand the raw specs, preserving order.
modules = list(parse_frozen_specs(destdir=MODULES_DIR))
+ # Regen build-related files.
+ regen_makefile(modules)
+ regen_pcbuild(modules)
+
# Freeze the target modules.
+ tmpsuffix = f'.{int(time.time())}'
for src in _iter_sources(modules):
- _freeze_module(src.frozenid, src.pyfile, src.frozenfile)
+ _freeze_module(src.frozenid, src.pyfile, src.frozenfile, tmpsuffix)
- # Regen build-related files.
- regen_manifest(modules)
+ # Regen files dependent of frozen file details.
regen_frozen(modules)
- regen_makefile(modules)
- regen_pcbuild(modules)
+ regen_manifest(modules)
if __name__ == '__main__':
update_file_with_tmpfile(filename, tmpfile)
-def update_file_with_tmpfile(filename, tmpfile):
- with open(filename, 'rb') as f:
- old_contents = f.read()
- with open(tmpfile, 'rb') as f:
- new_contents = f.read()
- if old_contents != new_contents:
+def update_file_with_tmpfile(filename, tmpfile, *, create=False):
+ try:
+ targetfile = open(filename, 'rb')
+ except FileNotFoundError:
+ if not create:
+ raise # re-raise
+ outcome = 'created'
os.replace(tmpfile, filename)
else:
- os.unlink(tmpfile)
+ with targetfile:
+ old_contents = targetfile.read()
+ with open(tmpfile, 'rb') as f:
+ new_contents = f.read()
+ # Now compare!
+ if old_contents != new_contents:
+ outcome = 'updated'
+ os.replace(tmpfile, filename)
+ else:
+ outcome = 'same'
+ os.unlink(tmpfile)
+ return outcome
if __name__ == '__main__':
- if len(sys.argv) != 3:
- print("Usage: %s <path to be updated> <path with new contents>" % (sys.argv[0],))
- sys.exit(1)
- update_file_with_tmpfile(sys.argv[1], sys.argv[2])
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--create', action='store_true')
+ parser.add_argument('--exitcode', action='store_true')
+ parser.add_argument('filename', help='path to be updated')
+ parser.add_argument('tmpfile', help='path with new contents')
+ args = parser.parse_args()
+ kwargs = vars(args)
+ setexitcode = kwargs.pop('exitcode')
+
+ outcome = update_file_with_tmpfile(**kwargs)
+ if setexitcode:
+ if outcome == 'same':
+ sys.exit(0)
+ elif outcome == 'updated':
+ sys.exit(1)
+ elif outcome == 'created':
+ sys.exit(2)
+ else:
+ raise NotImplementedError