|
| 1 | +#!/usr/bin/env python3 |
| 2 | +""" |
| 3 | +Generates .pte model, operator definitions, and header files |
| 4 | +""" |
| 5 | + |
| 6 | +import os |
| 7 | +import sys |
| 8 | +import subprocess |
| 9 | +import argparse |
| 10 | +from pathlib import Path |
| 11 | + |
| 12 | +def run_command(cmd, cwd=None, description=""): |
| 13 | + """Run a command and handle errors""" |
| 14 | + print(f"Running: {description}") |
| 15 | + print(f"Command: {' '.join(cmd)}") |
| 16 | + |
| 17 | + try: |
| 18 | + result = subprocess.run(cmd, cwd=cwd, check=True, capture_output=True, text=True) |
| 19 | + print(f"✓ {description} completed successfully") |
| 20 | + if result.stdout: |
| 21 | + print(f"Output: {result.stdout}") |
| 22 | + return result |
| 23 | + except subprocess.CalledProcessError as e: |
| 24 | + print(f"✗ {description} failed") |
| 25 | + print(f"Error: {e.stderr}") |
| 26 | + sys.exit(1) |
| 27 | + |
| 28 | +def main(): |
| 29 | + parser = argparse.ArgumentParser(description="Build ExecuTorch ARM Hello World model") |
| 30 | + parser.add_argument("--executorch-root", default="~/optional/modules/lib/executorch", |
| 31 | + help="Path to ExecuTorch root directory") |
| 32 | + parser.add_argument("--model-name", default="add", |
| 33 | + help="Name of the model (default: add)") |
| 34 | + parser.add_argument("--clean", action="store_true", |
| 35 | + help="Clean generated files before building") |
| 36 | + |
| 37 | + args = parser.parse_args() |
| 38 | + |
| 39 | + # Paths |
| 40 | + script_dir = Path(__file__).parent |
| 41 | + project_root = script_dir.parent.parent.parent.parent.parent.parent # Go up to petriok root |
| 42 | + executorch_root = project_root / args.executorch_root |
| 43 | + example_files_dir = "/home/zephyruser/zephyr/samples/modules/executorch/arm/hello_world/example_files" |
| 44 | + src_dir = script_dir / "src" |
| 45 | + |
| 46 | + model_name = args.model_name |
| 47 | + pte_file = f"{model_name}.pte" |
| 48 | + ops_def_file = "gen_ops_def.yml" |
| 49 | + header_file = "model_pte.h" |
| 50 | + |
| 51 | + print(f"Building ExecuTorch model: {model_name}") |
| 52 | + print(f"ExecuTorch root: {executorch_root}") |
| 53 | + print(f"Working directory: {script_dir}") |
| 54 | + |
| 55 | + # Clean previous build if requested |
| 56 | + if args.clean: |
| 57 | + files_to_clean = [pte_file, ops_def_file, src_dir / header_file] |
| 58 | + for file_path in files_to_clean: |
| 59 | + if Path(file_path).exists(): |
| 60 | + Path(file_path).unlink() |
| 61 | + print(f"Cleaned: {file_path}") |
| 62 | + |
| 63 | + # Step 1: Generate the .pte model file |
| 64 | + export_script = os.path.join(example_files_dir, f"export_{model_name}.py") |
| 65 | + if not os.path.exists(export_script): |
| 66 | + print(f"Error: Export script not found: {export_script}") |
| 67 | + sys.exit(1) |
| 68 | + |
| 69 | + try: |
| 70 | + run_command( |
| 71 | + [sys.executable, str(export_script)], |
| 72 | + cwd=script_dir, |
| 73 | + description="Generating .pte model file" |
| 74 | + ) |
| 75 | + except SystemExit: |
| 76 | + print(f"\n❌ Model generation failed. This is likely because PyTorch/ExecuTorch is not installed.") |
| 77 | + print(f"For now, using dummy model_pte.h for compilation testing.") |
| 78 | + print(f"To generate a real model, install PyTorch and ExecuTorch:") |
| 79 | + print(f" pip install torch") |
| 80 | + print(f" # Install ExecuTorch according to documentation") |
| 81 | + print(f" python build_model.py") |
| 82 | + return |
| 83 | + |
| 84 | + if not Path(script_dir / pte_file).exists(): |
| 85 | + print(f"Error: Model file {pte_file} was not generated") |
| 86 | + sys.exit(1) |
| 87 | + |
| 88 | + # Step 2: Generate operator definitions |
| 89 | + |
| 90 | + gen_ops_script = "/home/zephyruser/optional/modules/lib/executorch/codegen/tools/gen_ops_def.py" |
| 91 | + if not os.path.exists(gen_ops_script): |
| 92 | + print(f"Error: gen_ops_def.py not found at {gen_ops_script}") |
| 93 | + sys.exit(1) |
| 94 | + |
| 95 | + run_command( |
| 96 | + [sys.executable, str(gen_ops_script), |
| 97 | + "--output_path", ops_def_file, |
| 98 | + "--model_file_path", pte_file], |
| 99 | + cwd=script_dir, |
| 100 | + description="Generating operator definitions" |
| 101 | + ) |
| 102 | + |
| 103 | + # Step 3: Convert .pte to header file |
| 104 | + #pte_to_header_script = executorch_root / "examples" / "arm" / "executor_runner" / "pte_to_header.py" |
| 105 | + pte_to_header_script = "/home/zephyruser/optional/modules/lib/executorch/examples/arm/executor_runner/pte_to_header.py" |
| 106 | + if not os.path.exists(pte_to_header_script): |
| 107 | + print(f"Error: pte_to_header.py not found at {pte_to_header_script}") |
| 108 | + sys.exit(1) |
| 109 | + |
| 110 | + run_command( |
| 111 | + [sys.executable, str(pte_to_header_script), |
| 112 | + "--pte", pte_file, |
| 113 | + "--outdir", "src"], |
| 114 | + cwd=script_dir, |
| 115 | + description="Converting .pte to header file" |
| 116 | + ) |
| 117 | + |
| 118 | + # Step 4: Make the generated array const and remove section attribute |
| 119 | + header_path = src_dir / header_file |
| 120 | + if header_path.exists(): |
| 121 | + content = header_path.read_text() |
| 122 | + |
| 123 | + # Remove section attribute and replace with Zephyr alignment macro |
| 124 | + import re |
| 125 | + # Replace section+aligned pattern with Zephyr __ALIGN macro |
| 126 | + content = re.sub(r'__attribute__\s*\(\s*\(\s*section\s*\([^)]*\)\s*,\s*aligned\s*\(([^)]*)\)\s*\)\s*\)\s*', r'__ALIGN(\1) ', content) |
| 127 | + # Remove any remaining section-only attributes |
| 128 | + content = re.sub(r'__attribute__\s*\(\s*\(\s*section\s*\([^)]*\)\s*\)\s*\)\s*', '', content) |
| 129 | + # Also replace any standalone __attribute__((aligned(n))) with __ALIGN(n) |
| 130 | + content = re.sub(r'__attribute__\s*\(\s*\(\s*aligned\s*\(([^)]*)\)\s*\)\s*\)\s*', r'__ALIGN(\1) ', content) |
| 131 | + |
| 132 | + # Replace 'char model_pte_data[]' with 'const char model_pte_data[]' |
| 133 | + content = content.replace('char model_pte_data[]', 'const char model_pte_data[]') |
| 134 | + # Also handle 'char model_pte[]' variant |
| 135 | + content = content.replace('char model_pte[]', 'const char model_pte[]') |
| 136 | + |
| 137 | + header_path.write_text(content) |
| 138 | + print(f"✓ Made model data const and removed section attributes in {header_file}") |
| 139 | + else: |
| 140 | + print(f"Warning: Header file {header_file} not found") |
| 141 | + |
| 142 | + print("\n=== Build Summary ===") |
| 143 | + print(f"✓ Generated: {pte_file}") |
| 144 | + print(f"✓ Generated: {ops_def_file}") |
| 145 | + print(f"✓ Generated: src/{header_file}") |
| 146 | + print("\nNext steps:") |
| 147 | + print("1. Review gen_ops_def.yml and customize if needed") |
| 148 | + print("2. Build the Zephyr application with west build") |
| 149 | + |
| 150 | +if __name__ == "__main__": |
| 151 | + main() |
0 commit comments