modules: adding support for ROOTs definitions in zephyr/module.yml

Fixes: #25215

This commit introduces the possibility of defining ROOTs in a Zephyr
module and have it automatically appended to list of other ROOTs.
Supported with this commit:
- BOARD_ROOT
- SOC_ROOT
- DTS_ROOT
- ARCH_ROOT

In order to support this in Zephyr module files, the detection of west
has been moved to dedicated west.cmake file and included immediately
after python.cmake.

Also the inclusion of zephyr_modules.cmake has moved before first use
of BOARD_ROOT.

Signed-off-by: Torsten Rasmussen <Torsten.Rasmussen@nordicsemi.no>
diff --git a/scripts/zephyr_module.py b/scripts/zephyr_module.py
index 71e2b96..73798a1 100755
--- a/scripts/zephyr_module.py
+++ b/scripts/zephyr_module.py
@@ -48,6 +48,22 @@
         type: seq
         sequence:
           - type: str
+      settings:
+        required: false
+        type: map
+        mapping:
+          board_root:
+            required: false
+            type: str
+          dts_root:
+            required: false
+            type: str
+          soc_root:
+            required: false
+            type: str
+          arch_root:
+            required: false
+            type: str
   tests:
     required: false
     type: seq
@@ -124,6 +140,20 @@
     else:
         return ""
 
+def process_settings(module, meta):
+    section = meta.get('build', dict())
+    build_settings = section.get('settings', None)
+    out_text = ""
+
+    if build_settings is not None:
+        for root in ['board', 'dts', 'soc', 'arch']:
+            setting = build_settings.get(root+'_root', None)
+            if setting is not None:
+                root_path = PurePath(module) / setting
+                out_text += f'"{root.upper()}_ROOT":"{root_path}"\n'
+
+    return out_text
+
 def process_kconfig(module, meta):
     section = meta.get('build', dict())
     module_path = PurePath(module)
@@ -175,6 +205,9 @@
     parser.add_argument('--cmake-out',
                         help="""File to write with resulting <name>:<path>
                              values to use for including in CMake""")
+    parser.add_argument('--settings-out',
+                        help="""File to write with resulting <name>:<value>
+                             values to use for including in CMake""")
     parser.add_argument('-m', '--modules', nargs='+',
                         help="""List of modules to parse instead of using `west
                              list`""")
@@ -205,6 +238,7 @@
 
     kconfig = ""
     cmake = ""
+    settings = ""
     sanitycheck = ""
 
     Module = namedtuple('Module', ['project', 'meta', 'depends'])
@@ -259,6 +293,7 @@
     for module in sorted_modules:
         kconfig += process_kconfig(module.project, module.meta)
         cmake += process_cmake(module.project, module.meta)
+        settings += process_settings(module.project, module.meta)
         sanitycheck += process_sanitycheck(module.project, module.meta)
 
     if args.kconfig_out:
@@ -269,6 +304,10 @@
         with open(args.cmake_out, 'w', encoding="utf-8") as fp:
             fp.write(cmake)
 
+    if args.settings_out:
+        with open(args.settings_out, 'w', encoding="utf-8") as fp:
+            fp.write(settings)
+
     if args.sanitycheck_out:
         with open(args.sanitycheck_out, 'w', encoding="utf-8") as fp:
             fp.write(sanitycheck)