#!/usr/bin/env python3 # Copyright © 2020 Arm Ltd. All rights reserved. # Copyright 2020 NXP # SPDX-License-Identifier: MIT """This script executes SWIG commands to generate armnn and armnn version wrappers. This script cannot be moved to ./script dir because it uses find_armnn function from setup.py script. Both scripts must be in the same folder. """ import os import re import subprocess import argparse from setup import find_includes __current_dir = os.path.dirname(os.path.realpath(__file__)) __swig_exec = None __verbose = False SWIG_EXEC_ENV = "SWIG_EXECUTABLE" def get_swig_exec(swig_exec_env: str = SWIG_EXEC_ENV): """Returns the swig command. Uses either an env variable or the `swig` command and verifies it works. Args: swig_exec_env(str): Env variable pointing to the swig executable. Returns: str: Path to swig executable. Raises: RuntimeError: If unable to execute any version of swig. """ swig_exec = os.getenv(swig_exec_env) if swig_exec is None: swig_exec = "swig" if subprocess.Popen([swig_exec, "-version"], stdout=subprocess.DEVNULL): return swig_exec else: raise RuntimeError("Unable to execute swig.") def check_swig_version(expected_version: str): """Checks version of swig. Args: expected_version(str): String containing expected version. Returns: bool: True if version is correct, False otherwise """ cmd = subprocess.Popen([__swig_exec, "-version"], stdout=subprocess.PIPE) out, _ = cmd.communicate() pattern = re.compile(r"(?<=Version ).+(?=$)", re.MULTILINE) match = pattern.search(out.decode('utf-8')) if match: version_string = match.group(0).strip() if __verbose: print(f"SWIG version: {version_string}") return version_string.startswith(expected_version) else: return False def generate_wrap(name: str, extr_includes): """Generates the python wrapper using swig. Args: name(str): Name of the wrapper template. extr_includes(str): Include paths. Raises: RuntimeError: If wrapper fails to be generated. """ in_dir = os.path.join(__current_dir, "src", "pyarmnn", "swig") out_dir = os.path.join(__current_dir, "src", "pyarmnn", "_generated") if __verbose: print(f"Generating wrap for {name} ...") code = os.system(f"{__swig_exec} -c++ -python -Wall " + "-o {} ".format(os.path.join(out_dir, f"{name}_wrap.cpp")) + f"-outdir {out_dir} " + f"{extr_includes} " + f"-I{in_dir} " + os.path.join(in_dir, f"{name}.i")) if code != 0: raise RuntimeError(f"Failed to generate {name} ext.") if __name__ == "__main__": __swig_exec = get_swig_exec() # This check is redundant in case CMake is used, it's here for standalone use if not check_swig_version('4.'): raise RuntimeError("Wrong swig version was found. Expected SWIG version is 4.x.x") armnn_includes = find_includes() parser = argparse.ArgumentParser("Script to generate SWIG wrappers.") parser.add_argument("-v", "--verbose", help="Verbose output.", action="store_true") args = parser.parse_args() __verbose = args.verbose wrap_names = ['armnn_version', 'armnn', 'armnn_onnxparser', 'armnn_tfliteparser', 'armnn_deserializer'] for n in wrap_names: generate_wrap(n, f"-I{' -I'.join(armnn_includes)} ")