Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / compiler / one-cmds / one-codegen
index 5ccff0f..a956a63 100644 (file)
@@ -27,53 +27,15 @@ import ntpath
 import os
 import sys
 import shutil
+from types import SimpleNamespace
 
+import onelib.backends as backends
 import onelib.utils as oneutils
 
 # TODO Find better way to suppress trackback on error
 sys.tracebacklimit = 0
 
 
-def _get_backends_list():
-    """
-    [one hierarchy]
-    one
-    ├── backends
-    ├── bin
-    ├── doc
-    ├── include
-    ├── lib
-    └── test
-
-    The list where `one-codegen` finds its backends
-    - `bin` folder where `one-codegen` exists
-    - `backends` folder
-    - System path
-
-    NOTE If there are backends of the same name in different places,
-     the closer to the top in the list, the higher the priority.
-    """
-    dir_path = os.path.dirname(os.path.realpath(__file__))
-    backend_set = set()
-
-    # bin folder
-    files = [f for f in glob.glob(dir_path + '/*-compile')]
-    # backends folder
-    files += [
-        f for f in glob.glob(dir_path + '/../backends/**/*-compile', recursive=True)
-    ]
-    # TODO find backends in `$PATH`
-
-    backends_list = []
-    for cand in files:
-        base = ntpath.basename(cand)
-        if not base in backend_set and os.path.isfile(cand) and os.access(cand, os.X_OK):
-            backend_set.add(base)
-            backends_list.append(cand)
-
-    return backends_list
-
-
 def _get_parser(backends_list):
     codegen_usage = 'one-codegen [-h] [-v] [-C CONFIG] [-b BACKEND] [--] [COMMANDS FOR BACKEND]'
     parser = argparse.ArgumentParser(
@@ -94,15 +56,47 @@ def _get_parser(backends_list):
     return parser
 
 
-def _verify_arg(parser, args):
+def _verify_arg(parser, args, cfg_args, backend_args, unknown_args):
     """verify given arguments"""
+    cmd_backend_exist = oneutils.is_valid_attr(args, 'backend')
+    cfg_backend_exist = oneutils.is_valid_attr(cfg_args, 'backend')
+    cfg_backends_exist = oneutils.is_valid_attr(cfg_args, 'backends')
+
     # check if required arguments is given
     missing = []
-    if not oneutils.is_valid_attr(args, 'backend'):
+    if not cmd_backend_exist and not cfg_backend_exist and not cfg_backends_exist:
         missing.append('-b/--backend')
     if len(missing):
         parser.error('the following arguments are required: ' + ' '.join(missing))
 
+    if not oneutils.is_valid_attr(args, 'config'):
+        if not backend_args and not unknown_args:
+            parser.error('commands for the backend is missing.')
+
+    if cfg_backend_exist and cfg_backends_exist:
+        parser.error(
+            '\'backend\' option and \'backends\' option cannot be used simultaneously.')
+
+    # Check if given backend from command line exists in the configuration file
+    if cmd_backend_exist and cfg_backend_exist:
+        if args.backend != cfg_args.backend:
+            parser.error('Not found the command of given backend')
+
+    if cfg_backend_exist and not oneutils.is_valid_attr(cfg_args, 'command'):
+        parser.error('\'command\' key is missing in the configuration file.')
+
+    if cfg_backends_exist:
+        cfg_backends = getattr(cfg_args, 'backends').split(',')
+        # check if commands of given backends exist
+        for b in cfg_backends:
+            if not oneutils.is_valid_attr(cfg_args, b):
+                parser.error('Not found the command for ' + b)
+
+        # Check if given backend from command line exists in the configuration file
+        if cmd_backend_exist:
+            if args.backend not in cfg_backends:
+                parser.error('Not found the command of given backend')
+
 
 def _parse_arg(parser):
     codegen_args = []
@@ -134,36 +128,89 @@ def _parse_arg(parser):
 
 def main():
     # get backend list
-    backends_list = _get_backends_list()
+    backends_list = backends.get_list('compile')
 
     # parse arguments
     parser = _get_parser(backends_list)
     args, backend_args, unknown_args = _parse_arg(parser)
 
     # parse configuration file
-    oneutils.parse_cfg(args.config, 'one-codegen', args)
+    cfg_args = SimpleNamespace()
+    oneutils.parse_cfg(args.config, 'one-codegen', cfg_args)
+
+    # parse configuration file (args has arguments parsed from command line + cfg)
+    # oneutils.parse_cfg(args.config, 'one-codegen', args)
 
     # verify arguments
-    _verify_arg(parser, args)
-
-    # make a command to run given backend driver
-    codegen_path = None
-    backend_base = getattr(args, 'backend') + '-compile'
-    for cand in backends_list:
-        if ntpath.basename(cand) == backend_base:
-            codegen_path = cand
-    if not codegen_path:
-        # Find backend from system path
-        codegen_path = shutil.which(backend_base)
-
-    if not codegen_path:
-        raise FileNotFoundError(backend_base + ' not found')
-    codegen_cmd = [codegen_path] + backend_args + unknown_args
-    if oneutils.is_valid_attr(args, 'command'):
-        codegen_cmd += getattr(args, 'command').split()
-
-    # run backend driver
-    oneutils.run(codegen_cmd, err_prefix=backend_base)
+    _verify_arg(parser, args, cfg_args, backend_args, unknown_args)
+    '''
+    one-codegen defines its behavior for below cases.
+
+    [1] one-codegen -h
+    [2] one-codegen -v
+    [3] one-codegen -C ${cfg} (backend, command key in cfg)
+    [4] one-codegen -C ${cfg} (backends key in cfg)
+    [5] one-codegen -b ${backend} ${command}
+    [6] one-codegen -b ${backend} -- ${command}
+    [7] one-codegen -b ${backend} -C {cfg} (backend, command key in cfg)
+    [8] one-codegen -b ${backend} -C {cfg} (backends key in cfg) (Only 'backend' is invoked, 
+         even though cfg file has multiple backends)
+    [9] one-codegen -b ${backend} -C ${cfg} -- ${command} (backend, command key in cfg) 
+    [10] one-codegen -b ${backend} -C ${cfg} -- ${command} (backends key in cfg) (Only 'backend' is invoked, 
+         even though cfg file has multiple backends)
+
+    All other cases are not allowed or an undefined behavior.
+    '''
+    cmd_overwrite = False
+    if oneutils.is_valid_attr(args, 'config'):
+        # [9], [10]
+        if backend_args and not unknown_args:
+            given_backends = [args.backend]
+            cmd_overwrite = True
+        else:
+            # [7], [8]
+            if oneutils.is_valid_attr(args, 'backend'):
+                given_backends = [args.backend]
+                if oneutils.is_valid_attr(cfg_args, 'backend'):
+                    assert (oneutils.is_valid_attr(cfg_args, 'command'))
+                    setattr(cfg_args, args.backend, cfg_args.command)
+            else:
+                # [3]
+                if oneutils.is_valid_attr(cfg_args, 'backend'):
+                    assert (oneutils.is_valid_attr(cfg_args, 'command'))
+                    given_backends = [cfg_args.backend]
+                    setattr(cfg_args, cfg_args.backend, cfg_args.command)
+                # [4]
+                if oneutils.is_valid_attr(cfg_args, 'backends'):
+                    given_backends = cfg_args.backends.split(',')
+    # [5], [6]
+    else:
+        assert (backend_args or unknown_args)
+        given_backends = [args.backend]
+
+    for given_backend in given_backends:
+        # make a command to run given backend driver
+        codegen_path = None
+        backend_base = given_backend + '-compile'
+        for cand in backends_list:
+            if ntpath.basename(cand) == backend_base:
+                codegen_path = cand
+        if not codegen_path:
+            # Find backend from system path
+            codegen_path = shutil.which(backend_base)
+
+        if not codegen_path:
+            raise FileNotFoundError(backend_base + ' not found')
+
+        codegen_cmd = [codegen_path]
+        if not cmd_overwrite and oneutils.is_valid_attr(cfg_args, given_backend):
+            codegen_cmd += getattr(cfg_args, given_backend).split()
+        else:
+            codegen_cmd += backend_args
+            codegen_cmd += unknown_args
+
+        # run backend driver
+        oneutils.run(codegen_cmd, err_prefix=backend_base)
 
 
 if __name__ == '__main__':