8000 tools/mpremote: Add manifest function. · micropython/micropython@4ff9a53 · GitHub
[go: up one dir, main page]

Skip to content

Commit 4ff9a53

Browse files
committed
tools/mpremote: Add manifest function.
1 parent 6a7838d commit 4ff9a53

File tree

5 files changed

+193
-74
lines changed

5 files changed

+193
-74
lines changed

docs/reference/mpremote.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,23 @@ The full list of supported commands are:
141141
142142
$ mpremote umount
143143
144+
- compile a manifest.py from the current folder:
145+
146+
.. code-block:: bash
147+
148+
$ MPY_DIR=../../micropython
149+
$ PORT_DIR=../../micropython/ports/esp32
150+
$ mpremote manifest .
151+
152+
This will assemble / mpy-cross everything specified in the manifest.py into the folder ``_manifest``.
153+
If the current folder is also mounted, this folder will automatically be added to the path, eg:
154+
155+
.. code-block:: bash
156+
157+
$ mpremote manifest . mount .
158+
159+
A soft-reset will re-process the manifest file to include any local updates.
160+
144161
Multiple commands can be specified and they will be run sequentially.
145162

146163

tools/makemanifest.py

Lines changed: 98 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,20 @@ def freeze_mpy(path, script=None, opt=0):
135135
KIND_MPY = 3
136136

137137
VARS = {}
138+
MPY_CROSS = None
139+
MPY_TOOL = None
138140

139141
manifest_list = []
140142

141143

144+
QUIET = False
145+
146+
147+
def log(*args):
148+
if not QUIET:
149+
print(*args)
150+
151+
142152
class IncludeOptions:
143153
def __init__(self, **kwargs):
144154
self._kwargs = kwargs
@@ -166,7 +176,12 @@ def system(cmd):
166176
def convert_path(path):
167177
# Perform variable substituion.
168178
for name, value in VARS.items():
169-
path = path.replace("$({})".format(name), value)
179+
pattern = "$({})".format(name)
180+
if value is not None:
181+
path = path.replace(pattern, value)
182+
elif pattern in path:
183+
raise SystemExit("{} variable must be specified".format(name))
184+
170185
# Convert to absolute path (so that future operations don't rely on
171186
# still being chdir'ed).
172187
return os.path.abspath(path)
@@ -225,7 +240,7 @@ def freeze_internal(kind, path, script, opt):
225240
kind = k
226241
break
227242
else:
228-
print("warn: unsupported file type, skipped freeze: {}".format(script))
243+
log("warn: unsupported file type, skipped freeze: {}".format(script))
229244
return
230245
wanted_extension = extension_kind[kind]
231246
if not script.endswith(wanted_extension):
@@ -325,23 +340,42 @@ def main():
325340
VARS[name] = value
326341

327342
if "MPY_DIR" not in VARS or "PORT_DIR" not in VARS:
328-
print("MPY_DIR and PORT_DIR variables must be specified")
343+
log.error("MPY_DIR and PORT_DIR variables must be specified")
329344
sys.exit(1)
330345

331-
# Get paths to tools
332-
MPY_CROSS = VARS["MPY_DIR"] + "/mpy-cross/mpy-cross"
333-
if sys.platform == "win32":
334-
MPY_CROSS += ".exe"
335-
MPY_CROSS = os.getenv("MICROPY_MPYCROSS", MPY_CROSS)
336-
MPY_TOOL = VARS["MPY_DIR"] + "/tools/mpy-tool.py"
346+
process(
347+
args.files,
348+
args.build_dir,
349+
args.output,
350+
args.mpy_tool_flags,
351+
args.mpy_cross_flags,
352+
)
337353

338-
# Ensure mpy-cross is built
354+
355+
def process(files, build_dir, output=None, mpy_tool_flags="", mpy_cross_flags=""):
356+
# Get paths to tools
357+
global MPY_CROSS, MPY_TOOL
358+
if MPY_CROSS is None:
359+
MPY_CROSS = VARS["MPY_DIR"] + "/mpy-cross/mpy-cross"
360+
if sys.platform == "win32":
361+
MPY_CROSS += ".exe"
362+
MPY_CROSS = os.getenv("MICROPY_MPYCROSS", MPY_CROSS)
363+
if MPY_TOOL is None:
364+
MPY_TOOL = VARS["MPY_DIR"] + "/tools/mpy-tool.py"
365+
366+
# Ensure mpy-cross is built / available
367+
if not os.path.exists(MPY_CROSS):
368+
try:
369+
from mpy_cross import mpy_cross
370+
MPY_CROSS = mpy_cross
371+
except ImportError:
372+
pass
339373
if not os.path.exists(MPY_CROSS):
340374
print("mpy-cross not found at {}, please build it first".format(MPY_CROSS))
341375
sys.exit(1)
342376

343377
# Include top-level inputs, to generate the manifest
344-
for input_manifest in args.files:
378+
for input_manifest in files:
345379
try:
346380
if input_manifest.endswith(".py"):
347381
include(input_manifest)
@@ -354,29 +388,32 @@ def main():
354388
# Process the manifest
355389
str_paths = []
356390
mpy_files = []
391+
new_files = []
357392
ts_newest = 0
358393
for kind, path, script, opt in manifest_list:
359394
if kind == KIND_AS_STR:
360395
str_paths.append(path)
361396
ts_outfile = get_timestamp_newest(path)
362397
elif kind == KIND_AS_MPY:
363398
infile = "{}/{}".format(path, script)
364-
outfile = "{}/frozen_mpy/{}.mpy".format(args.build_dir, script[:-3])
399+
subdir = "frozen_mpy" if output else ""
400+
outfile = "{}/{}/{}.mpy".format(build_dir, subdir, script[:-3])
365401
ts_infile = get_timestamp(infile)
366402
ts_outfile = get_timestamp(outfile, 0)
367403
if ts_infile >= ts_outfile:
368-
print("MPY", script)
404+
log("MPY", script)
369405
mkdir(outfile)
370406
res, out = system(
371407
[MPY_CROSS]
372-
+ args.mpy_cross_flags.split()
408+
+ mpy_cross_flags.split()
373409
+ ["-o", outfile, "-s", script, "-O{}".format(opt), infile]
374410
)
375411
if res != 0:
376412
print("error compiling {}:".format(infile))
377413
sys.stdout.buffer.write(out)
378414
raise SystemExit(1)
379415
ts_outfile = get_timestamp(outfile)
416+
new_files.append(outfile)
380417
mpy_files.append(outfile)
381418
else:
382419
assert kind == KIND_MPY
@@ -385,50 +422,53 @@ def main():
385422
ts_outfile = get_timestamp(infile)
386423
ts_newest = max(ts_newest, ts_outfile)
387424

388-
# Check if output file needs generating
389-
if ts_newest < get_timestamp(args.output, 0):
390-
# No files are newer than output file so it does not need updating
391-
return
392-
393-
# Freeze paths as strings
394-
output_str = generate_frozen_str_content(str_paths)
395-
396-
# Freeze .mpy files
397-
if mpy_files:
398-
res, output_mpy = system(
399-
[
400-
sys.executable,
401-
MPY_TOOL,
402-
"-f",
403-
"-q",
404-
args.build_dir + "/genhdr/qstrdefs.preprocessed.h",
405-
]
406-
+ args.mpy_tool_flags.split()
407-
+ mpy_files
408-
)
409-
if res != 0:
410-
print("error freezing mpy {}:".format(mpy_files))
411-
print(output_mpy.decode())
412-
sys.exit(1)
413-
else:
414-
output_mpy = (
415-
b'#include "py/emitglue.h"\n'
416-
b"extern const qstr_pool_t mp_qstr_const_pool;\n"
417-
b"const qstr_pool_t mp_qstr_frozen_const_pool = {\n"
418-
b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0\n"
419-
b"};\n"
420-
b'const char mp_frozen_names[] = { MP_FROZEN_STR_NAMES "\\0"};\n'
421-
b"const mp_raw_code_t *const mp_frozen_mpy_content[] = {NULL};\n"
422-
)
423-
424-
# Generate output
425-
print("GEN", args.output)
426-
mkdir(args.output)
427-
with open(args.output, "wb") as f:
428-
f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n")
429-
f.write(output_str)
430-
f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n")
431-
f.write(output_mpy)
425+
if output:
426+
# Check if output file needs generating
427+
if ts_newest < get_timestamp(output, 0):
428+
# No files are newer than output file so it does not need updating
429+
return
430+
431+
# Freeze paths as strings
432+
output_str = generate_frozen_str_content(str_paths)
433+
434+
# Freeze .mpy files
435+
if mpy_files:
436+
res, output_mpy = system(
437+
[
438+
sys.executable,
439+
MPY_TOOL,
440+
"-f",
441+
"-q",
442+
build_dir + "/genhdr/qstrdefs.preprocessed.h",
443+
]
444+
+ mpy_tool_flags.split()
445+
+ mpy_files
446+
)
447+
if res != 0:
448+
print("error freezing mpy {}:".format(mpy_files))
449+
print(output_mpy.decode())
450+
sys.exit(1)
451+
else:
452+
output_mpy = (
453+
b'#include "py/emitglue.h"\n'
454+
b"extern const qstr_pool_t mp_qstr_const_pool;\n"
455+
b"const qstr_pool_t mp_qstr_frozen_const_pool = {\n"
456+
b" (qstr_pool_t*)&mp_qstr_const_pool, MP_QSTRnumber_of, 0, 0\n"
457+
b"};\n"
458+
b'const char mp_frozen_names[] = { MP_FROZEN_STR_NAMES "\\0"};\n'
459+
b"const mp_raw_code_t *const mp_frozen_mpy_content[] = {NULL};\n"
460+
)
461+
462+
# Generate output
463+
log("GEN {}".format(output))
464+
mkdir(output)
465+
with open(output, "wb") as f:
466+
f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_STR\n//\n")
467+
f.write(output_str)
468+
f.write(b"//\n// Content for MICROPY_MODULE_FROZEN_MPY\n//\n")
469+
f.write(output_mpy)
470+
471+
return mpy_files, new_files
432472

433473

434474
if __name__ == "__main__":

tools/mpremote/mpremote/main.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@
4242
"disconnect": (False, False, 0, "disconnect current device"),
4343
"resume": (False, False, 0, "resume a previous mpremote session (will not auto soft-reset)"),
4444
"soft-reset": (False, True, 0, "perform a soft-reset of the device"),
45+
"manifest": (
46+
True,
47+
False,
48+
1,
49+
"compile manifest.py",
50+
),
4551
"mount": (True, False, 1, "mount local directory on device"),
4652
"umount": (True, False, 0, "unmount the local directory"),
4753
"repl": (
@@ -275,7 +281,7 @@ def do_filesystem(pyb, args):
275281
args.pop(0)
276282
assert args[-1] == ":"
277283
args.pop()
278-
cp_recursive(args)
284+
pyb.cp_recursiv 83A7 e(args)
279285
else:
280286
pyboard.filesystem_command(pyb, args)
281287
args.clear()
@@ -517,6 +523,9 @@ def main():
517523
elif cmd == "soft-reset":
518524
pyb.enter_raw_repl(soft_reset=True)
519525
auto_soft_reset = False
526+
elif cmd == "manifest":
527+
path = args.pop(0)
528+
pyb.build_manifest(path)
520529
elif cmd == "mount":
521530
path = args.pop(0)
522531
pyb.mount_local(path)

0 commit comments

Comments
 (0)
0