Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,7 @@ PYTHON= python$(EXE)
BUILDPYTHON= python$(BUILDEXE)

PYTHON_FOR_REGEN=@PYTHON_FOR_REGEN@
UPDATE_FILE=@PYTHON_FOR_REGEN@ $(srcdir)/Tools/scripts/update_file.py
PYTHON_FOR_BUILD=@PYTHON_FOR_BUILD@
_PYTHON_HOST_PLATFORM=@_PYTHON_HOST_PLATFORM@
BUILD_GNU_TYPE= @build@
Expand Down Expand Up @@ -691,12 +692,14 @@ regen-importlib: Programs/_freeze_importlib
# from Lib/importlib/_bootstrap_external.py using _freeze_importlib
./Programs/_freeze_importlib \
$(srcdir)/Lib/importlib/_bootstrap_external.py \
$(srcdir)/Python/importlib_external.h
$(srcdir)/Python/importlib_external.h.new
$(UPDATE_FILE) $(srcdir)/Python/importlib_external.h $(srcdir)/Python/importlib_external.h.new
# Regenerate Python/importlib.h from Lib/importlib/_bootstrap.py
# using _freeze_importlib
./Programs/_freeze_importlib \
$(srcdir)/Lib/importlib/_bootstrap.py \
$(srcdir)/Python/importlib.h
$(srcdir)/Python/importlib.h.new
$(UPDATE_FILE) $(srcdir)/Python/importlib.h $(srcdir)/Python/importlib.h.new

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a little bit boring to always have to repeat the full path. Why not passing a single parameter to the update script, and add ".new" to get the "new filename"?

@pitrou pitrou Sep 20, 2017

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because it doesn't impose a naming convention and makes it explicit which files are operated on. Also, there's a lot of boredom in Makefiles ;-)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. It was just a suggestion, being explicit is fine.

Also, there's a lot of boredom in Makefiles ;-)

I will not start discussing that aspect of Makefiles, thanks.



############################################################################
Expand Down Expand Up @@ -770,8 +773,10 @@ regen-grammar: $(PGEN)
# from Grammar/Grammar using pgen
@$(MKDIR_P) Include
$(PGEN) $(srcdir)/Grammar/Grammar \
$(srcdir)/Include/graminit.h \
$(srcdir)/Python/graminit.c
$(srcdir)/Include/graminit.h.new \
$(srcdir)/Python/graminit.c.new
$(UPDATE_FILE) $(srcdir)/Include/graminit.h $(srcdir)/Include/graminit.h.new
$(UPDATE_FILE) $(srcdir)/Python/graminit.c $(srcdir)/Python/graminit.c.new

Parser/grammar.o: $(srcdir)/Parser/grammar.c \
$(srcdir)/Include/token.h \
Expand All @@ -789,21 +794,24 @@ regen-ast:
# Regenerate Include/Python-ast.h using Parser/asdl_c.py -h
$(MKDIR_P) $(srcdir)/Include
$(PYTHON_FOR_REGEN) $(srcdir)/Parser/asdl_c.py \
-h $(srcdir)/Include \
-h $(srcdir)/Include/Python-ast.h.new \
$(srcdir)/Parser/Python.asdl
$(UPDATE_FILE) $(srcdir)/Include/Python-ast.h $(srcdir)/Include/Python-ast.h.new
# Regenerate Python/Python-ast.c using Parser/asdl_c.py -c
$(MKDIR_P) $(srcdir)/Python
$(PYTHON_FOR_REGEN) $(srcdir)/Parser/asdl_c.py \
-c $(srcdir)/Python \
-c $(srcdir)/Python/Python-ast.c.new \
$(srcdir)/Parser/Python.asdl
$(UPDATE_FILE) $(srcdir)/Python/Python-ast.c $(srcdir)/Python/Python-ast.c.new

.PHONY: regen-opcode
regen-opcode:
# Regenerate Include/opcode.h from Lib/opcode.py
# using Tools/scripts/generate_opcode_h.py
$(PYTHON_FOR_REGEN) $(srcdir)/Tools/scripts/generate_opcode_h.py \
$(srcdir)/Lib/opcode.py \
$(srcdir)/Include/opcode.h
$(srcdir)/Include/opcode.h.new
$(UPDATE_FILE) $(srcdir)/Include/opcode.h $(srcdir)/Include/opcode.h.new

Python/compile.o Python/symtable.o Python/ast.o: $(srcdir)/Include/graminit.h $(srcdir)/Include/Python-ast.h

Expand Down Expand Up @@ -860,7 +868,8 @@ regen-opcode-targets:
# Regenerate Python/opcode_targets.h from Lib/opcode.py
# using Python/makeopcodetargets.py
$(PYTHON_FOR_REGEN) $(srcdir)/Python/makeopcodetargets.py \
$(srcdir)/Python/opcode_targets.h
$(srcdir)/Python/opcode_targets.h.new
$(UPDATE_FILE) $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/opcode_targets.h.new

Python/ceval.o: $(srcdir)/Python/opcode_targets.h $(srcdir)/Python/ceval_gil.h

Expand All @@ -887,7 +896,8 @@ regen-typeslots:
# using Objects/typeslots.py
$(PYTHON_FOR_REGEN) $(srcdir)/Objects/typeslots.py \
< $(srcdir)/Include/typeslots.h \
$(srcdir)/Objects/typeslots.inc
$(srcdir)/Objects/typeslots.inc.new
$(UPDATE_FILE) $(srcdir)/Objects/typeslots.inc $(srcdir)/Objects/typeslots.inc.new

############################################################################
# Header files
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Avoid wholesale rebuild after `make regen-all` if nothing changed.
80 changes: 38 additions & 42 deletions Parser/asdl_c.py
Original file line number Diff line number Diff line change
Expand Up @@ -1285,59 +1285,55 @@ def main(srcfile, dump_module=False):
print(mod)
if not asdl.check(mod):
sys.exit(1)
if INC_DIR:
p = "%s/%s-ast.h" % (INC_DIR, mod.name)
f = open(p, "w")
f.write(auto_gen_msg)
f.write('#include "asdl.h"\n\n')
c = ChainOfVisitors(TypeDefVisitor(f),
StructVisitor(f),
PrototypeVisitor(f),
)
c.visit(mod)
f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n")
f.write("int PyAST_Check(PyObject* obj);\n")
f.close()

if SRC_DIR:
p = os.path.join(SRC_DIR, str(mod.name) + "-ast.c")
f = open(p, "w")
f.write(auto_gen_msg)
f.write('#include <stddef.h>\n')
f.write('\n')
f.write('#include "Python.h"\n')
f.write('#include "%s-ast.h"\n' % mod.name)
f.write('\n')
f.write("static PyTypeObject AST_type;\n")
v = ChainOfVisitors(
PyTypesDeclareVisitor(f),
PyTypesVisitor(f),
Obj2ModPrototypeVisitor(f),
FunctionVisitor(f),
ObjVisitor(f),
Obj2ModVisitor(f),
ASTModuleVisitor(f),
PartingShots(f),
)
v.visit(mod)
f.close()
if H_FILE:
with open(H_FILE, "w") as f:
f.write(auto_gen_msg)
f.write('#include "asdl.h"\n\n')
c = ChainOfVisitors(TypeDefVisitor(f),
StructVisitor(f),
PrototypeVisitor(f),
)
c.visit(mod)
f.write("PyObject* PyAST_mod2obj(mod_ty t);\n")
f.write("mod_ty PyAST_obj2mod(PyObject* ast, PyArena* arena, int mode);\n")
f.write("int PyAST_Check(PyObject* obj);\n")

if C_FILE:
with open(C_FILE, "w") as f:
f.write(auto_gen_msg)
f.write('#include <stddef.h>\n')
f.write('\n')
f.write('#include "Python.h"\n')
f.write('#include "%s-ast.h"\n' % mod.name)
f.write('\n')
f.write("static PyTypeObject AST_type;\n")
v = ChainOfVisitors(
PyTypesDeclareVisitor(f),
PyTypesVisitor(f),
Obj2ModPrototypeVisitor(f),
FunctionVisitor(f),
ObjVisitor(f),
Obj2ModVisitor(f),
ASTModuleVisitor(f),
PartingShots(f),
)
v.visit(mod)

if __name__ == "__main__":
import getopt

INC_DIR = ''
SRC_DIR = ''
H_FILE = ''
C_FILE = ''
dump_module = False
opts, args = getopt.getopt(sys.argv[1:], "dh:c:")
for o, v in opts:
if o == '-h':
INC_DIR = v
H_FILE = v
if o == '-c':
SRC_DIR = v
C_FILE = v
if o == '-d':
dump_module = True
if INC_DIR and SRC_DIR:
if H_FILE and C_FILE:
print('Must specify exactly one output file')
sys.exit(1)
elif len(args) != 1:
Expand Down
28 changes: 28 additions & 0 deletions Tools/scripts/update_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
A script that replaces an old file with a new one, only if the contents
actually changed. If not, the new file is simply deleted.

This avoids wholesale rebuilds when a code (re)generation phase does not
actually change the in-tree generated code.
"""

import os
import sys


def main(old_path, new_path):
with open(old_path, 'rb') as f:
old_contents = f.read()
with open(new_path, 'rb') as f:
new_contents = f.read()
if old_contents != new_contents:
os.replace(new_path, old_path)
else:
os.unlink(new_path)


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)
main(sys.argv[1], sys.argv[2])