[PATCH rtems 01/12] bsp/imxrt: Add script to import mcux-sdk
Christian Mauderer
christian.mauderer at embedded-brains.de
Thu May 4 15:00:42 UTC 2023
NXP now offers the support library in a mcux-sdk git repository instead
of in zip files. The git repository supports multiple controllers of the
i.MXRT family instead of a single one.
This commit adds a script that is a (very hacky) parser for the the
cmake files in the mcux-sdk. It copies all necessary files and creates
yml spec files for the controllers that have been imported.
The script is only intended as a helper for updating the files. It is
not necessary for using the BSP.
---
bsps/arm/imxrt/import_from_mcux_sdk.py | 293 +++++++++++++++++++++++++
1 file changed, 293 insertions(+)
create mode 100755 bsps/arm/imxrt/import_from_mcux_sdk.py
diff --git a/bsps/arm/imxrt/import_from_mcux_sdk.py b/bsps/arm/imxrt/import_from_mcux_sdk.py
new file mode 100755
index 0000000000..2dfe224865
--- /dev/null
+++ b/bsps/arm/imxrt/import_from_mcux_sdk.py
@@ -0,0 +1,293 @@
+#!/usr/bin/env python3
+
+""" Parse the cmake files from mcux_sdk and import the sources to RTEMS.
+This script is a ugly hack and it might doesn't work with newer mcux_sdk
+versions.
+
+Provide a number of the cmake files in `devices/MIMXRT*/all_lib_device_*.cmake`
+as parameter to this script. The file format is expected to be quite fixed.
+Don't give anything else to the script. It won't work.
+"""
+
+import argparse
+import logging
+from enum import Enum
+from pathlib import Path
+import re
+from slugify import slugify
+import shutil
+import yaml
+
+class states(Enum):
+ IDLE = 0
+ ADD_MODULE_PATH = 1
+ ADD_CFILES = 2
+ ADD_HFILES = 3
+ SKIP_TILL_ENDIF = 4
+
+def find_file(name, paths):
+ for p in paths:
+ path = Path(p)
+ f = path / f'{name}.cmake'
+ if f.exists():
+ return f.resolve(strict=True)
+ return None
+
+def get_path_from_line(line, cmake, rel_to = None):
+ current_list_dir = str(Path(cmake.name).parent.resolve())
+ path = line.strip().replace("${CMAKE_CURRENT_LIST_DIR}", current_list_dir)
+ path = Path(path)
+ if rel_to is not None:
+ p = Path(path)
+ path = p.relative_to(rel_to)
+ return path
+
+def parse_cmake(cmake, mcux_device, module_path = [], rel_to = None, stack = []):
+ logger.info(f"Parse file: {cmake.name}")
+ if rel_to is None:
+ rel_to = Path(cmake.name).parent.resolve()
+ mod_path = module_path.copy()
+ state = states.IDLE
+ cfiles = []
+ hpaths = []
+
+ # prevent loops
+ if cmake.name in stack:
+ logger.warning(f"Loop detected: {' -> '.join(stack)}")
+ return cfiles, hpaths
+ # Use a shallow copy!
+ stack_work = stack[:] + [cmake.name]
+
+ for line in cmake:
+ logger.debug(f"state: {state}; file: {cmake.name}; line '{line.strip()}'")
+
+ if state == states.IDLE:
+ if "if(${MCUX_DEVICE} STREQUAL " in line:
+ equal_to = re.search(r'"(.*)"', line).group(1)
+ if equal_to == mcux_device:
+ logger.debug(f"MCUX matches {equal_to}")
+ else:
+ logger.debug(f"MCUX ({mcux_device}) not equal to {equal_to}")
+ state = states.SKIP_TILL_ENDIF
+ elif "endif()" in line:
+ state = states.IDLE
+ elif ("list" in line) and ("APPEND" in line) and ("CMAKE_MODULE_PATH" in line):
+ state = states.ADD_MODULE_PATH
+ elif ("target_sources" in line):
+ state = states.ADD_CFILES
+ elif ("target_include_directories" in line):
+ state = states.ADD_HFILES
+ elif ("include(" in line):
+ # NOTE: This will also include commented lines. This is
+ # necessary because NXP only added the includes as an example to
+ # the all_lib_device_*.cmake files.
+ to_include = re.search(r"\((.*)\)", line).group(1)
+ included = find_file(to_include, mod_path)
+ logger.debug(f"Search include file: {to_include}; found {included}")
+ if included is None:
+ # log unexpected misses
+ if not (to_include.startswith("middleware") or \
+ to_include.startswith("CMSIS")):
+ logger.error(f"can't find {to_include}")
+ elif "rtos" in to_include:
+ logger.info("Skip include for other RTOS: ${to_include}")
+ elif "utility" in to_include:
+ logger.info("Skip utilities: ${to_include}")
+ elif "caam" in to_include:
+ logger.info("Filter non working driver: ${to_include}")
+ elif included.relative_to(rel_to).parts[0] == "drivers" or \
+ included.relative_to(rel_to).parts[0] == "devices":
+ # we are only interested in drivers
+ with open(included, "r") as f:
+ cf, hp = parse_cmake(f, mcux_device, mod_path, rel_to, stack_work)
+ cfiles += cf
+ hpaths += hp
+ else:
+ logger.debug(f"Ignore included file: {to_include} found at {included}")
+
+ elif state == states.SKIP_TILL_ENDIF:
+ if "endif()" in line:
+ state = states.IDLE
+
+ elif state == states.ADD_MODULE_PATH:
+ if ")" in line:
+ state = states.IDLE
+ else:
+ path = rel_to / get_path_from_line(line, cmake, rel_to)
+ logger.info(f"Appended path {str(path)}")
+ mod_path += [path]
+
+ elif state == states.ADD_CFILES:
+ if ")" in line:
+ state = states.IDLE
+ else:
+ cf = get_path_from_line(line, cmake, rel_to)
+ logger.debug(f"Appended c-file {str(cf)}")
+ cfiles += [cf]
+
+ elif state == states.ADD_HFILES:
+ if ")" in line:
+ state = states.IDLE
+ else:
+ hp = get_path_from_line(line, cmake, rel_to)
+ logger.debug(f"Appended header path {str(hp)}")
+ hpaths += [hp]
+
+ logger.info(f"Parsing file done: {cmake.name}")
+ logger.debug(f" Found {cfiles}, {hpaths}")
+ return cfiles, hpaths
+
+class mcux_device:
+ name = None
+ cfiles = []
+ hpaths = []
+
+ def __init__(self, name, cfiles = [], hpaths = []):
+ self.name = name
+ self.cfiles = cfiles
+ self.hpaths = hpaths
+
+ def __str__(self):
+ cfiles = ', '.join([str(cf) for cf in self.cfiles])
+ hpaths = ', '.join([str(hp) for hp in self.hpaths])
+ return f"MCUX {self.name}: cfiles: ({cfiles}), hpaths: ({hpaths})"
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument(
+ "cmake",
+ help="Path to all_devices.cmake",
+ type=argparse.FileType('r'),
+ )
+ parser.add_argument(
+ "MCUX_DEVICE",
+ help="Values for MCUX_DEVICE that should be used",
+ type=str,
+ nargs='+',
+ )
+ parser.add_argument(
+ "-l", "--loglevel",
+ help = "Define log level.",
+ type = str.upper,
+ choices = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'],
+ default = 'INFO',
+ )
+ parser.add_argument(
+ "-r", "--rtems",
+ help = "RTEMS base path",
+ required = True,
+ )
+ parser.add_argument(
+ "-c", "--copy",
+ action = 'store_true',
+ )
+ parser.add_argument(
+ "-t", "--collect",
+ action = 'store_true',
+ )
+
+ args = parser.parse_args()
+
+ numeric_loglevel = getattr(logging, args.loglevel)
+ logging.basicConfig(level = numeric_loglevel)
+ logger = logging.getLogger("mcux")
+ logger.debug(f"Started with the following options: {args}")
+
+ devices = []
+
+ # get c-files and header paths from mcux SDK
+ for mcux in args.MCUX_DEVICE:
+ args.cmake.seek(0)
+ cf, hp = parse_cmake(args.cmake, mcux)
+ devices += [mcux_device(mcux, cf, hp)]
+
+ if args.collect:
+ # find files common in multiple devices
+ common_cfiles = set.intersection(*[set(d.cfiles) for d in devices])
+ common_hpaths = set.intersection(*[set(d.hpaths) for d in devices])
+ common = mcux_device("common",
+ sorted(list(common_cfiles)), sorted(list(common_hpaths)))
+
+ # remove common parts from devices
+ for d in devices:
+ d.cfiles = sorted(list(set(d.cfiles) - common_cfiles))
+ d.hpaths = sorted(list(set(d.hpaths) - common_hpaths))
+
+ devices += [common]
+ else:
+ # Only sort files and make sure to have them only once
+ for d in devices:
+ d.cfiles = sorted(list(set(d.cfiles)))
+ d.hpaths = sorted(list(set(d.hpaths)))
+
+ for d in devices:
+ logger.info(str(d))
+
+ # Now for the interesting part: Copying sources and generating yml files
+ mcux_path = Path(args.cmake.name).parent.resolve()
+ rtems_path = Path(args.rtems)
+ rtems_mcux_path = Path("bsps/arm/imxrt/mcux-sdk")
+ for d in devices:
+ yml_file = Path(args.rtems) / "spec" / "build" / "bsps" / "arm" / \
+ "imxrt" / f"obj-{slugify(d.name)}.yml"
+ yml = {
+ "SPDX-License-Identifier": "CC-BY-SA-4.0 OR BSD-2-Clause",
+ "build-type": "objects",
+ "cflags": [],
+ "copyrights":
+ ["Copyright (C) 2023 embedded brains GmbH (http://www.embedded-brains.de)"],
+ "cppflags": [],
+ "cxxflags": [],
+ "ldflags": [],
+ "enabled-by": True,
+ "includes": [],
+ "install": [
+ {
+ "destination": "${BSP_INCLUDEDIR}",
+ "source": [],
+ }
+ ],
+ "links": [
+ {
+ "role": "build-dependency",
+ "uid": "grp",
+ }
+ ],
+ "source": [],
+ "type": "build",
+ "use-after": [],
+ "use-before": [],
+ }
+
+ # Process source files
+ for cf in d.cfiles:
+ logger.info(f"Processing {cf}")
+ cf_rtems = rtems_mcux_path / cf
+ if args.copy:
+ dst = rtems_path / cf_rtems
+ src = mcux_path / cf
+ dst.parent.mkdir(parents=True, exist_ok=True)
+ dst.write_bytes(src.read_bytes())
+ yml["source"] += [str(cf_rtems)]
+
+ # Process header files
+ for hp in d.hpaths:
+ logger.info(f"Processing {hp}")
+ hp_rtems = rtems_mcux_path / hp
+ yml["includes"] += [str(hp_rtems)]
+ dst_path = rtems_path / hp_rtems
+ src_path = mcux_path / hp
+ if args.copy:
+ dst_path.mkdir(parents=True, exist_ok=True)
+
+ for h_src in sorted(src_path.glob("*.h")):
+ h_rel = h_src.relative_to(mcux_path)
+ h_dst = rtems_mcux_path / h_rel
+ yml["install"][0]["source"] += [str(h_dst)]
+ if args.copy:
+ (rtems_path / h_dst).write_bytes(h_src.read_bytes())
+
+ # Write yml
+ with open(yml_file, 'w') as out:
+ yaml.dump(yml, out)
+ logger.info(f"Written to {yml_file}")
--
2.35.3
More information about the devel
mailing list