Skip to content

Commit fc3d7ae

Browse files
dlechdpgeorge
authored andcommitted
py/make_root_pointers: Add MP_REGISTER_ROOT_POINTER parser/generator.
This adds new compile-time infrastructure to parse source code files for `MP_REGISTER_ROOT_POINTER()` and generates a new `root_pointers.h` header file containing the collected declarations. This works the same as the existing `MP_REGISTER_MODULE()` feature. Signed-off-by: David Lechner <[email protected]>
1 parent a8d78cc commit fc3d7ae

File tree

10 files changed

+154
-12
lines changed

10 files changed

+154
-12
lines changed

Diff for: ports/cc3200/bootmgr/bootloader.mk

+4
Original file line numberDiff line numberDiff line change
@@ -134,3 +134,7 @@ $(HEADER_BUILD)/mpversion.h: | $(HEADER_BUILD)
134134
# Create an empty "moduledefs.h" needed by py/mkrules.mk
135135
$(HEADER_BUILD)/moduledefs.h: | $(HEADER_BUILD)
136136
touch $@
137+
138+
# Create an empty "root_pointers.h" needed by py/mkrules.mk
139+
$(HEADER_BUILD)/root_pointers.h: | $(HEADER_BUILD)
140+
touch $@

Diff for: ports/stm32/mboot/Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -213,21 +213,25 @@ PREFIX_FILE = ../boards/stm32f4xx_prefix.c
213213
BOARD_PINS = $(BOARD_DIR)/pins.csv
214214
HEADER_BUILD = $(BUILD)/genhdr
215215
GEN_QSTRDEFS_GENERATED = $(HEADER_BUILD)/qstrdefs.generated.h
216+
GEN_ROOT_POINTERS = $(HEADER_BUILD)/root_pointers.h
216217
GEN_PINS_SRC = $(BUILD)/pins_$(BOARD).c
217218
GEN_PINS_HDR = $(HEADER_BUILD)/pins.h
218219
GEN_PINS_QSTR = $(HEADER_BUILD)/pins_qstr.h
219220
GEN_PINS_AF_CONST = $(HEADER_BUILD)/pins_af_const.h
220221
GEN_PINS_AF_DEFS = $(HEADER_BUILD)/pins_af_defs.h
221222
GEN_PINS_AF_PY = $(BUILD)/pins_af.py
222223

223-
$(OBJ): $(GEN_QSTRDEFS_GENERATED) $(GEN_PINS_AF_DEFS)
224+
$(OBJ): $(GEN_QSTRDEFS_GENERATED) $(GEN_ROOT_POINTERS) $(GEN_PINS_AF_DEFS)
224225

225226
$(HEADER_BUILD):
226227
$(MKDIR) -p $(BUILD)/genhdr
227228

228229
$(GEN_QSTRDEFS_GENERATED): | $(HEADER_BUILD)
229230
$(Q)echo "// empty" > $@
230231

232+
$(GEN_ROOT_POINTERS): | $(HEADER_BUILD)
233+
$(Q)echo "// empty" > $@
234+
231235
$(GEN_PINS_AF_DEFS): $(BOARD_PINS) $(MAKE_PINS) ../$(AF_FILE) $(PREFIX_FILE) | $(HEADER_BUILD)
232236
$(ECHO) "GEN $@"
233237
$(Q)$(PYTHON) $(MAKE_PINS) --board $(BOARD_PINS) --af ../$(AF_FILE) \

Diff for: ports/windows/msvc/genhdr.targets

+18-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<Import Project="paths.props" Condition="'$(PyPathsIncluded)' != 'True'"/>
55

66
<!--Generate qstrdefs.generated.h and mpversion.h similar to what is done in py/mkrules.mk and py/py.mk-->
7-
<Target Name="GenerateHeaders" DependsOnTargets="MakeVersionHdr;MakeModuleDefs;MakeQstrData">
7+
<Target Name="GenerateHeaders" DependsOnTargets="MakeVersionHdr;MakeModuleDefs;MakeRootPointers;MakeQstrData">
88
</Target>
99

1010
<PropertyGroup>
@@ -15,6 +15,7 @@
1515
<QstrDefsCollected>$(DestDir)qstrdefscollected.h</QstrDefsCollected>
1616
<QstrGen>$(DestDir)qstrdefs.generated.h</QstrGen>
1717
<ModuleDefsCollected>$(DestDir)/moduledefs.collected</ModuleDefsCollected>
18+
<RootPointersCollected>$(DestDir)/root_pointers.collected</RootPointersCollected>
1819
<PyPython Condition="'$(PyPython)' == ''">$(MICROPY_CPYTHON3)</PyPython>
1920
<PyPython Condition="'$(PyPython)' == ''">python</PyPython>
2021
<CLToolExe Condition="'$(CLToolExe)' == ''">cl.exe</CLToolExe>
@@ -45,7 +46,7 @@
4546
using(var outFile = System.IO.File.CreateText(OutputFile)) {
4647
foreach(var inFile in InputFiles)
4748
foreach(var line in System.IO.File.ReadAllLines(inFile))
48-
if((line.Contains(".c") && line.StartsWith("#line")) || line.Contains("MP_QSTR"))
49+
if((line.Contains(".c") && line.StartsWith("#line")) || line.Contains("MP_QSTR") || line.Contains("MP_REGISTER"))
4950
outFile.WriteLine( line );
5051
}
5152
]]>
@@ -114,6 +115,20 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) {
114115
<MSBuild Projects="$(MSBuildThisFileFullPath)" Targets="CopyFileIfDifferent" Properties="SourceFile=$(TmpFile);DestFile=$(DestFile)"/>
115116
</Target>
116117

118+
<Target Name="CollectRootPointers" DependsOnTargets="MakeQstrDefs" Inputs="$(DestDir)qstr.i.last" Outputs="$(RootPointersCollected)">
119+
<Exec Command="$(PyPython) $(PySrcDir)makeqstrdefs.py split root_pointer $(DestDir)qstr.i.last $(DestDir)root_pointer _"/>
120+
<Exec Command="$(PyPython) $(PySrcDir)makeqstrdefs.py cat root_pointer _ $(DestDir)root_pointer $(RootPointersCollected)"/>
121+
</Target>
122+
123+
<Target Name="MakeRootPointers" DependsOnTargets="CollectRootPointers" Inputs="$(PySrcDir)make_root_pointers.py;$(RootPointersCollected)" Outputs="$(DestDir)root_pointers.h">
124+
<PropertyGroup>
125+
<DestFile>$(DestDir)root_pointers.h</DestFile>
126+
<TmpFile>$(DestFile).tmp</TmpFile>
127+
</PropertyGroup>
128+
<Exec Command="$(PyPython) $(PySrcDir)make_root_pointers.py $(RootPointersCollected) > $(TmpFile)"/>
129+
<MSBuild Projects="$(MSBuildThisFileFullPath)" Targets="CopyFileIfDifferent" Properties="SourceFile=$(TmpFile);DestFile=$(DestFile)"/>
130+
</Target>
131+
117132
<Target Name="MakeQstrData" DependsOnTargets="MakeQstrDefs" Inputs="$(QstrDefsCollected);$(PyQstrDefs);$(QstrDefs)" Outputs="$(QstrGen)">
118133
<PropertyGroup>
119134
<TmpFile>$(QstrGen).tmp</TmpFile>
@@ -132,7 +147,7 @@ using(var outFile = System.IO.File.CreateText(OutputFile)) {
132147
<MSBuild Projects="$(MSBuildThisFileFullPath)" Targets="CopyFileIfDifferent" Properties="SourceFile=$(TmpFile);DestFile=$(DestFile)"/>
133148
</Target>
134149

135-
<Target Name="FreezeModules" Condition="'$(FrozenManifest)' != ''" DependsOnTargets="MakeQstrData" Inputs="$(FrozenManifest)" Outputs="$(PyBuildDir)frozen_content.c">
150+
<Target Name="FreezeModules" Condition="'$(FrozenManifest)' != ''" DependsOnTargets="MakeQstrData;MakeRootPointers" Inputs="$(FrozenManifest)" Outputs="$(PyBuildDir)frozen_content.c">
136151
<ItemGroup>
137152
<ClCompile Include="$(PyBuildDir)frozen_content.c"/>
138153
<ClCompile>

Diff for: py/make_root_pointers.py

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
"""
2+
This pre-processor parses a single file containing a list of
3+
MP_REGISTER_ROOT_POINTER(variable declaration) items.
4+
5+
These are used to generate a header with the required entries for
6+
"struct _mp_state_vm_t" in py/mpstate.h
7+
"""
8+
9+
from __future__ import print_function
10+
11+
import argparse
12+
import io
13+
import re
14+
15+
16+
PATTERN = re.compile(r"MP_REGISTER_ROOT_POINTER\((.*?)\);")
17+
18+
19+
def find_root_pointer_registrations(filename):
20+
"""Find any MP_REGISTER_ROOT_POINTER definitions in the provided file.
21+
22+
:param str filename: path to file to check
23+
:return: List[variable_declaration]
24+
"""
25+
with io.open(filename, encoding="utf-8") as c_file_obj:
26+
return set(re.findall(PATTERN, c_file_obj.read()))
27+
28+
29+
def generate_root_pointer_header(root_pointers):
30+
"""Generate header with root pointer entries.
31+
32+
:param List[variable_declaration] root_pointers: root pointer declarations
33+
:return: None
34+
"""
35+
36+
# Print header file for all external modules.
37+
print("// Automatically generated by make_root_pointers.py.")
38+
print()
39+
40+
for item in root_pointers:
41+
print(item, end=";")
42+
print()
43+
44+
45+
def main():
46+
parser = argparse.ArgumentParser()
47+
parser.add_argument("file", nargs=1, help="file with MP_REGISTER_ROOT_POINTER definitions")
48+
args = parser.parse_args()
49+
50+
root_pointers = find_root_pointer_registrations(args.file[0])
51+
generate_root_pointer_header(sorted(root_pointers))
52+
53+
54+
if __name__ == "__main__":
55+
main()

Diff for: py/makeqstrdefs.py

+9-2
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
# Extract MP_REGISTER_MODULE(...) macros.
2525
_MODE_MODULE = "module"
2626

27+
# Extract MP_REGISTER_ROOT_POINTER(...) macros.
28+
_MODE_ROOT_POINTER = "root_pointer"
29+
2730

2831
def is_c_source(fname):
2932
return os.path.splitext(fname)[1] in [".c"]
@@ -90,6 +93,8 @@ def process_file(f):
9093
re_match = re.compile(r'MP_COMPRESSED_ROM_TEXT\("([^"]*)"\)')
9194
elif args.mode == _MODE_MODULE:
9295
re_match = re.compile(r"MP_REGISTER_MODULE\(.*?,\s*.*?\);")
96+
elif args.mode == _MODE_ROOT_POINTER:
97+
re_match = re.compile(r"MP_REGISTER_ROOT_POINTER\(.*?\);")
9398
output = []
9499
last_fname = None
95100
for line in f:
@@ -111,7 +116,7 @@ def process_file(f):
111116
if args.mode == _MODE_QSTR:
112117
name = match.replace("MP_QSTR_", "")
113118
output.append("Q(" + name + ")")
114-
elif args.mode in (_MODE_COMPRESS, _MODE_MODULE):
119+
elif args.mode in (_MODE_COMPRESS, _MODE_MODULE, _MODE_ROOT_POINTER):
115120
output.append(match)
116121

117122
if last_fname:
@@ -148,6 +153,8 @@ def cat_together():
148153
mode_full = "Compressed data"
149154
elif args.mode == _MODE_MODULE:
150155
mode_full = "Module registrations"
156+
elif args.mode == _MODE_ROOT_POINTER:
157+
mode_full = "Root pointer registrations"
151158
if old_hash != new_hash:
152159
print(mode_full, "updated")
153160
try:
@@ -208,7 +215,7 @@ class Args:
208215
args.output_dir = sys.argv[4]
209216
args.output_file = None if len(sys.argv) == 5 else sys.argv[5] # Unused for command=split
210217

211-
if args.mode not in (_MODE_QSTR, _MODE_COMPRESS, _MODE_MODULE):
218+
if args.mode not in (_MODE_QSTR, _MODE_COMPRESS, _MODE_MODULE, _MODE_ROOT_POINTER):
212219
print("error: mode %s unrecognised" % sys.argv[2])
213220
sys.exit(2)
214221

Diff for: py/mkrules.cmake

+30
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ set(MICROPY_QSTRDEFS_GENERATED "${MICROPY_GENHDR_DIR}/qstrdefs.generated.h")
1111
set(MICROPY_MODULEDEFS_SPLIT "${MICROPY_GENHDR_DIR}/moduledefs.split")
1212
set(MICROPY_MODULEDEFS_COLLECTED "${MICROPY_GENHDR_DIR}/moduledefs.collected")
1313
set(MICROPY_MODULEDEFS "${MICROPY_GENHDR_DIR}/moduledefs.h")
14+
set(MICROPY_ROOT_POINTERS_SPLIT "${MICROPY_GENHDR_DIR}/root_pointers.split")
15+
set(MICROPY_ROOT_POINTERS_COLLECTED "${MICROPY_GENHDR_DIR}/root_pointers.collected")
16+
set(MICROPY_ROOT_POINTERS "${MICROPY_GENHDR_DIR}/root_pointers.h")
1417

1518
# Need to do this before extracting MICROPY_CPP_DEF below. Rest of frozen
1619
# manifest handling is at the end of this file.
@@ -46,6 +49,7 @@ target_sources(${MICROPY_TARGET} PRIVATE
4649
${MICROPY_MPVERSION}
4750
${MICROPY_QSTRDEFS_GENERATED}
4851
${MICROPY_MODULEDEFS}
52+
${MICROPY_ROOT_POINTERS}
4953
)
5054

5155
# Command to force the build of another command
@@ -139,6 +143,31 @@ add_custom_command(
139143
DEPENDS ${MICROPY_MODULEDEFS_COLLECTED}
140144
)
141145

146+
# Generate root_pointers.h
147+
148+
add_custom_command(
149+
OUTPUT ${MICROPY_ROOT_POINTERS_SPLIT}
150+
COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py split root_pointer ${MICROPY_GENHDR_DIR}/qstr.i.last ${MICROPY_GENHDR_DIR}/root_pointer _
151+
COMMAND touch ${MICROPY_ROOT_POINTERS_SPLIT}
152+
DEPENDS ${MICROPY_QSTRDEFS_LAST}
153+
VERBATIM
154+
COMMAND_EXPAND_LISTS
155+
)
156+
157+
add_custom_command(
158+
OUTPUT ${MICROPY_ROOT_POINTERS_COLLECTED}
159+
COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/makeqstrdefs.py cat root_pointer _ ${MICROPY_GENHDR_DIR}/root_pointer ${MICROPY_ROOT_POINTERS_COLLECTED}
160+
DEPENDS ${MICROPY_ROOT_POINTERS_SPLIT}
161+
VERBATIM
162+
COMMAND_EXPAND_LISTS
163+
)
164+
165+
add_custom_command(
166+
OUTPUT ${MICROPY_ROOT_POINTERS}
167+
COMMAND ${Python3_EXECUTABLE} ${MICROPY_PY_DIR}/make_root_pointers.py ${MICROPY_ROOT_POINTERS_COLLECTED} > ${MICROPY_ROOT_POINTERS}
168+
DEPENDS ${MICROPY_ROOT_POINTERS_COLLECTED} ${MICROPY_PY_DIR}/make_root_pointers.py
169+
)
170+
142171
# Build frozen code if enabled
143172

144173
if(MICROPY_FROZEN_MANIFEST)
@@ -174,6 +203,7 @@ if(MICROPY_FROZEN_MANIFEST)
174203
COMMAND ${Python3_EXECUTABLE} ${MICROPY_DIR}/tools/makemanifest.py -o ${MICROPY_FROZEN_CONTENT} -v "MPY_DIR=${MICROPY_DIR}" -v "MPY_LIB_DIR=${MICROPY_LIB_DIR}" -v "PORT_DIR=${MICROPY_PORT_DIR}" -v "BOARD_DIR=${MICROPY_BOARD_DIR}" -b "${CMAKE_BINARY_DIR}" -f${MICROPY_CROSS_FLAGS} ${MICROPY_FROZEN_MANIFEST}
175204
DEPENDS MICROPY_FORCE_BUILD
176205
${MICROPY_QSTRDEFS_GENERATED}
206+
${MICROPY_ROOT_POINTERS}
177207
${MICROPY_MPYCROSS_DEPENDENCY}
178208
VERBATIM
179209
)

Diff for: py/mkrules.mk

+13-3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ endif
77
# Extra deps that need to happen before object compilation.
88
OBJ_EXTRA_ORDER_DEPS =
99

10-
# Generate moduledefs.h.
11-
OBJ_EXTRA_ORDER_DEPS += $(HEADER_BUILD)/moduledefs.h
10+
# Generate header files.
11+
OBJ_EXTRA_ORDER_DEPS += $(HEADER_BUILD)/moduledefs.h $(HEADER_BUILD)/root_pointers.h
1212

1313
ifeq ($(MICROPY_ROM_TEXT_COMPRESSION),1)
1414
# If compression is enabled, trigger the build of compressed.data.h...
@@ -126,6 +126,16 @@ $(HEADER_BUILD)/moduledefs.collected: $(HEADER_BUILD)/moduledefs.split
126126
$(ECHO) "GEN $@"
127127
$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat module _ $(HEADER_BUILD)/module $@
128128

129+
# Module definitions via MP_REGISTER_ROOT_POINTER.
130+
$(HEADER_BUILD)/root_pointers.split: $(HEADER_BUILD)/qstr.i.last
131+
$(ECHO) "GEN $@"
132+
$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py split root_pointer $< $(HEADER_BUILD)/root_pointer _
133+
$(Q)$(TOUCH) $@
134+
135+
$(HEADER_BUILD)/root_pointers.collected: $(HEADER_BUILD)/root_pointers.split
136+
$(ECHO) "GEN $@"
137+
$(Q)$(PYTHON) $(PY_SRC)/makeqstrdefs.py cat root_pointer _ $(HEADER_BUILD)/root_pointer $@
138+
129139
# Compressed error strings.
130140
$(HEADER_BUILD)/compressed.split: $(HEADER_BUILD)/qstr.i.last
131141
$(ECHO) "GEN $@"
@@ -165,7 +175,7 @@ endif
165175

166176
ifneq ($(FROZEN_MANIFEST),)
167177
# to build frozen_content.c from a manifest
168-
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h | $(MICROPY_MPYCROSS_DEPENDENCY)
178+
$(BUILD)/frozen_content.c: FORCE $(BUILD)/genhdr/qstrdefs.generated.h $(BUILD)/genhdr/root_pointers.h | $(MICROPY_MPYCROSS_DEPENDENCY)
169179
$(Q)$(MAKE_MANIFEST) -o $@ -v "MPY_DIR=$(TOP)" -v "MPY_LIB_DIR=$(MPY_LIB_DIR)" -v "PORT_DIR=$(shell pwd)" -v "BOARD_DIR=$(BOARD_DIR)" -b "$(BUILD)" $(if $(MPY_CROSS_FLAGS),-f"$(MPY_CROSS_FLAGS)",) --mpy-tool-flags="$(MPY_TOOL_FLAGS)" $(FROZEN_MANIFEST)
170180
endif
171181

Diff for: py/mpstate.h

+7
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,13 @@ typedef struct _mp_state_vm_t {
192192
// include any root pointers defined by a port
193193
MICROPY_PORT_ROOT_POINTERS
194194

195+
// Include any root pointers registered with MP_REGISTER_ROOT_POINTER().
196+
#ifndef NO_QSTR
197+
// Only include root pointer definitions when not doing qstr extraction, because
198+
// the qstr extraction stage also generates the root pointers header file.
199+
#include "genhdr/root_pointers.h"
200+
#endif
201+
195202
// root pointers for extmod
196203

197204
#if MICROPY_REPL_EVENT_DRIVEN

Diff for: py/obj.h

+8-3
Original file line numberDiff line numberDiff line change
@@ -416,13 +416,18 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;
416416
#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name}
417417
#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_rom_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name}
418418

419+
#ifndef NO_QSTR
420+
419421
// Declare a module as a builtin, processed by makemoduledefs.py
420422
// param module_name: MP_QSTR_<module name>
421423
// param obj_module: mp_obj_module_t instance
422-
423-
#ifndef NO_QSTR
424424
#define MP_REGISTER_MODULE(module_name, obj_module)
425-
#endif
425+
426+
// Declare a root pointer (to avoid garbage collection of a global static variable).
427+
// param variable_declaration: a valid C variable declaration
428+
#define MP_REGISTER_ROOT_POINTER(variable_declaration)
429+
430+
#endif // NO_QSTR
426431

427432
// Underlying map/hash table implementation (not dict object or map function)
428433

Diff for: py/py.mk

+5
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ $(HEADER_BUILD)/moduledefs.h: $(HEADER_BUILD)/moduledefs.collected
218218
@$(ECHO) "GEN $@"
219219
$(Q)$(PYTHON) $(PY_SRC)/makemoduledefs.py $< > $@
220220

221+
# build a list of registered root pointers for py/mpstate.h.
222+
$(HEADER_BUILD)/root_pointers.h: $(HEADER_BUILD)/root_pointers.collected $(PY_SRC)/make_root_pointers.py
223+
@$(ECHO) "GEN $@"
224+
$(Q)$(PYTHON) $(PY_SRC)/make_root_pointers.py $< > $@
225+
221226
# Standard C functions like memset need to be compiled with special flags so
222227
# the compiler does not optimise these functions in terms of themselves.
223228
CFLAGS_BUILTIN ?= -ffreestanding -fno-builtin -fno-lto

0 commit comments

Comments
 (0)