def compile(main_py, metadata): """Compiles a main.py file into a main.mpy file. Parameters ---------- main_py : str The main.py file metadata : dict firmware metadata Returns ------- bytes compiled main.mpy binary blob """ out, _ = mpy_cross.run('--version', stdout=subprocess.PIPE).communicate() mpy_version = int(out.decode().strip()[-1]) if mpy_version != metadata['mpy-abi-version']: print('Firmware package expects mpy-cross ABI ' + f'v{metadata["mpy-abi-version"]:} but we have v{mpy_version}', file=sys.stderr) exit(1) with tempfile.TemporaryDirectory('lpf2-flasher') as tmp_dir: with open(os.path.join(tmp_dir, 'main.py'), 'w') as f: f.write(main_py) code = mpy_cross.run( *metadata['mpy-cross-options'], 'main.py', cwd=tmp_dir, ).wait() if code: exit(code) with open(os.path.join(tmp_dir, 'main.mpy'), 'rb') as f: return f.read()
def convert_to_mpy(): for root, dirs, files in os.walk("MPY"): root = root.replace("\\", "/") for file in files: if ".py" == file[-3:] and file != "main.py": py_path = root + "/" + file mpy_cross.run(py_path).wait() os.remove(py_path)
def compile_tree_inline(directory): import mpy_cross files_touched = [] for py_file in walk_pyfiles(directory): log.info('Compiling "{}" using mpy-cross'.format(py_file)) mpy_cross.run(py_file) mpy_file = py_file.replace('.py', '.mpy') files_touched.append(mpy_file) return files_touched
def mpy_cross_process(*args): with mpy_cross.run(*args, stdout=PIPE) as proc: while True: line = proc.stdout.readline().decode("utf-8") if not line: break print(line.rstrip())
def cross_compile(): files = [] for build_file in glob.iglob(os.path.join(build_dir, "**", "*.py"), recursive=True): if os.path.isfile(build_file): target_file = build_file.replace(build_dir, x_build_dir).replace( '.py', '.mpy') target_dir = os.path.split(target_file)[0] os.makedirs(target_dir, exist_ok=True) print(target_file) mpy_cross.run("-o", target_file, build_file) files.append((build_file, target_file)) sleep(0.1) for build_file, target_file in files: copystat(build_file, target_file) copyfile(os.path.join(lib_dir, 'boot.py'), os.path.join(x_build_dir, 'boot.py'))
def cross_compile(input_path: Path) -> Path: output_path = COMPILE_DIR / (".".join(input_path.name.split(".")[:-1]) + ".mpy") mpy_cross_process = mpy_cross.run(input_path, "-o", output_path) if mpy_cross_process.wait() == 0: return output_path else: exit("Something bad happened!")
def cross_compile(file): print('cross_compile {}'.format(file)) name, ext = os.path.splitext(file) out = os.path.join(OUT_DIR, name + '.mpy') try: os.makedirs(os.path.dirname(out)) except FileExistsError: pass p = mpy_cross.run(file, '-o', out) p.wait() return out
def compile_py_to_mpy(py_file_path: str, mpy_file_path: str) -> Error: """ Cross-compiles the given .py file into a .mpy file. Assumes destination directory already exists. """ # Remarks: # - Use "stdout=subprocess.PIPE" to capture the standard output. # - https://docs.python.org/3/library/subprocess.html#subprocess.PIPE # - Use "stderr=subprocess.STDOUT" to redirect stderr to stdout. # - https://stackoverflow.com/questions/11495783/redirect-subprocess-stderr-to-stdout # - Best practice dictates to call proc.kill() and invoke proc.communicate() again after a timeout occurs. # - https://docs.python.org/3/library/subprocess.html#subprocess.Popen.communicate # - Popen.communicate() waits (blocks) until the process terminates or the timeout occurs. timeout_sec = 5.0 timed_out = False args = [ "-mno-unicode", "-msmall-int-bits=31", py_file_path, "-o", mpy_file_path ] log("mpy_cross %s" % " ".join(args)) proc: subprocess.Popen = mpy_cross.run(*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) try: stdout_data, _ = proc.communicate(timeout=timeout_sec) except subprocess.TimeoutExpired: proc.kill() stdout_data, _ = proc.communicate() timed_out = True log(stdout_data.decode("utf-8")) if timed_out: return Error("%s: mpy_cross failed! It took too long! timeout_sec=%s" % (func(), timeout_sec)) if proc.returncode != 0: return Error("%s: mpy_cross failed! Exit status: %s" % (func(), proc.returncode)) return Success
pass else: os.mkdir('../compiled/MicroWebSrv2') if os.path.exists('../compiled/MicroWebSrv2/libs'): pass else: os.mkdir('../compiled/MicroWebSrv2/libs') if os.path.exists('../compiled/MicroWebSrv2/mods'): pass else: os.mkdir('../compiled/MicroWebSrv2/mods') for i in os.listdir(workPath): if i.endswith('.py') and i not in ['gzipper.py', 'main.py', 'test_pid.py']: print("Compiling: " + i) mpy_cross.run(workPath + '/' + i) for i in os.listdir(workPath): print("cleaning workSpace...") if i.endswith('.mpy'): shutil.move(workPath + '/' + i, '../compiled/' + i) else: pass #pack MicroWebSrv2 into bytecode MWS = workPath+'/'+'MicroWebSrv2' for i in os.listdir(MWS): if i.endswith('.py'): print("Compiling: " + i) mpy_cross.run(MWS + '/' + i)
def exec_cmd(cmd): print('*** Exec: {}'.format(cmd)) os.system(cmd) print_with_header('Erase Flash (Press "Boot" button to connect)') exec_cmd('esptool.py --chip esp32 --port {} erase_flash'.format(port)) print_with_header('Write Firmware') exec_cmd( 'esptool.py --chip esp32 --port {} --baud 460800 write_flash -z 0x1000 {}'. format(port, fw)) print_with_header('Write Application Files') for f in files: if f != 'boot.py' and f.endswith('.py'): print('*** Precompiling: {}'.format(f)) mpy_return_code = mpy_cross.run(f).wait(2000) if mpy_return_code != 0: print('!!! Unexpected return code: {}'.format(mpy_return_code)) f = f.replace('.py', '.mpy') if not os.path.exists(f): print('!!! path does not exist: {}'.format(f)) else: exec_cmd('ampy --port {} put "{}"'.format(port, f)) if f.endswith('.mpy'): os.remove(f) print_with_header('Done')
def uminify(arguments): """ Args: arguments: Returns: None Raises: ValueError: When filename does not exists. """ def log_it(*args, **kwargs): """Wrapper function in order to print verbose output. Args: *args: Arguments to be passed to the print function. **kwargs: Keyword Arguments to be passed to the print function. Returns: None """ if arguments.verbose: print(*args, flush=True, **kwargs) input_file = os.path.abspath(arguments.filename) intermediate_filename = os.path.join( os.path.dirname(os.path.abspath(arguments.filename)), f"i{os.path.basename(os.path.abspath(arguments.filename))}") output_file = os.path.abspath(arguments.output) output_dir = os.path.dirname(os.path.abspath(output_file)) if not os.path.exists(input_file): raise ValueError(f"Seems like the path {input_file} do not exists.") # Get input_file size. input_size = get_file_size(input_file) log_it(f"{input_file}: {input_size} B") # Minify the code. result = minify_code(input_file) # Check whether the output directory exists if not create it. if not os.path.exists(output_dir): log_it(f"Creating {output_dir} directory.") os.makedirs(output_dir, exist_ok=True) # Write minified content to a intermediate file. with open(intermediate_filename, 'w') as inter_file: inter_file.write(result) # Get the file size of the generated intermediate file. intermediate_size = get_file_size(intermediate_filename) log_it(f"{intermediate_filename}: {intermediate_size} B") # Convert Python code into mpy byte code. compilation_execution = mpy_cross.run("-o", output_file, intermediate_filename) # Wait for the process to be finished. compilation_execution.wait() # Get the output_file size. output_size = get_file_size(output_file) log_it(f"{output_file}: {output_size} B") # Remove intermediate file created if everything when Ok. if not compilation_execution.returncode and os.path.exists( intermediate_filename): if not arguments.keep: log_it(f"Deleting {intermediate_filename}") os.remove(intermediate_filename) log_it( f"\n{TColors.bold + TColors.okgreen}{input_size - output_size} Bytes reduced.{TColors.endc}" )
import hashlib import os from functools import partial LIB = '../mpy_robot_tools/' MPY_LIB = 'mpy/' INSTALLER = 'install_mpy_robot_tools.py' BASE_SCRIPT = 'base_script.py' files = [f for f in os.listdir(LIB) if f not in ['__pycache__']] encoded = [] for f in files: out_file = f.split(".")[0] + ".mpy" out_file_loc = MPY_LIB + out_file mpy_cross.run('-march=armv6', LIB + f, '-o', out_file_loc) time.sleep(0.5) with open(out_file_loc, 'rb') as mpy_file: file_hash = hashlib.sha256(mpy_file.read()).hexdigest() chunks = [] with open(out_file_loc, 'rb') as mpy_file: for chunk in iter(partial(mpy_file.read, 2**10), b''): chunks += [binascii.b2a_base64(chunk).decode('utf-8')] print(out_file, ": ", len(chunks), " chunks of ", 2**10) encoded += [(out_file, tuple(chunks), file_hash)] spike_code = open(BASE_SCRIPT, 'r').read() with open(INSTALLER, 'w') as f: f.write(spike_code.format(repr(tuple(encoded))))