You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.7 KiB
149 lines
4.7 KiB
""" |
|
Utility script to migrate Zephyr-based projects to normative POSIX Kconfig options. |
|
|
|
This script should be used for migrating from versions of Zephyr older than v3.7.0 to Zephyr |
|
version v3.7.0 or later. |
|
|
|
Usage:: |
|
|
|
python $ZEPHYR_BASE/scripts/utils/migrate_posix_kconfigs.py --root root_path --dry-run |
|
|
|
The utility will process c, cpp, h, hpp, rst, conf, CMakeLists.txt, |
|
yml, yaml and Kconfig files. |
|
|
|
|
|
Copyright (c) 2022 Nordic Semiconductor ASA |
|
Copyright (c) 2024 Tenstorrent AI ULC |
|
SPDX-License-Identifier: Apache-2.0 |
|
""" |
|
|
|
import argparse |
|
import re |
|
import sys |
|
from pathlib import Path |
|
|
|
ZEPHYR_BASE = Path(__file__).parents[2] |
|
|
|
FILE_PATTERNS = ( |
|
r".+\.c", r".+\.cpp", r".+\.hpp", r".+\.h", r".+\.rst", r".+\.conf", |
|
r".+\.yml", r".+\.yaml", r"CMakeLists.txt", r"Kconfig(\..+)?" |
|
) |
|
|
|
REPLACEMENTS = { |
|
"EVENTFD_MAX": "ZVFS_EVENTFD_MAX", |
|
"FNMATCH": "POSIX_C_LIB_EXT", |
|
"GETENTROPY": "POSIX_C_LIB_EXT", |
|
"GETOPT": "POSIX_C_LIB_EXT", |
|
"MAX_PTHREAD_COUNT": "POSIX_THREAD_THREADS_MAX", |
|
"MAX_PTHREAD_KEY_COUNT": "POSIX_THREAD_KEYS_MAX", |
|
"MAX_TIMER_COUNT": "POSIX_TIMER_MAX", |
|
"MSG_COUNT_MAX": "POSIX_MQ_OPEN_MAX", |
|
"POSIX_CLOCK": "POSIX_TIMERS", |
|
"POSIX_CONFSTR": "POSIX_SINGLE_PROCESS", |
|
"POSIX_ENV": "POSIX_SINGLE_PROCESS", |
|
"POSIX_FS": "POSIX_FILE_SYSTEM", |
|
"POSIX_LIMITS_RTSIG_MAX": "POSIX_RTSIG_MAX", |
|
"POSIX_MAX_FDS": "ZVFS_OPEN_MAX", |
|
"POSIX_MAX_OPEN_FILES": "ZVFS_OPEN_MAX", |
|
"POSIX_MQUEUE": "POSIX_MESSAGE_PASSING", |
|
"POSIX_PUTMSG": "XOPEN_STREAMS", |
|
"POSIX_SIGNAL": "POSIX_SIGNALS", |
|
"POSIX_SYSCONF": "POSIX_SINGLE_PROCESS", |
|
"POSIX_SYSLOG": "XSI_SYSTEM_LOGGING", |
|
"POSIX_UNAME": "POSIX_SINGLE_PROCESS", |
|
"PTHREAD": "POSIX_THREADS", |
|
"PTHREAD_BARRIER": "POSIX_BARRIERS", |
|
"PTHREAD_COND": "POSIX_THREADS", |
|
"PTHREAD_IPC": "POSIX_THREADS", |
|
"PTHREAD_KEY": "POSIX_THREADS", |
|
"PTHREAD_MUTEX": "POSIX_THREADS", |
|
"PTHREAD_RWLOCK": "POSIX_READER_WRITER_LOCKS", |
|
"PTHREAD_SPINLOCK": "POSIX_SPIN_LOCKS", |
|
"TIMER": "POSIX_TIMERS", |
|
"TIMER_DELAYTIMER_MAX": "POSIX_DELAYTIMER_MAX", |
|
"SEM_NAMELEN_MAX": "POSIX_SEM_NAME_MAX", |
|
"SEM_VALUE_MAX": "POSIX_SEM_VALUE_MAX", |
|
} |
|
|
|
MESSAGES = { |
|
"POSIX_CLOCK": |
|
"POSIX_CLOCK is a one-to-many replacement. If this simple substitution is not " |
|
"sufficient, it's best to try a combination of POSIX_CLOCK_SELECTION, POSIX_CPUTIME, " |
|
"POSIX_MONOTONIC_CLOCK, POSIX_TIMERS, and POSIX_TIMEOUTS.", |
|
"POSIX_MAX_FDS": |
|
"A read-only version of this symbol is POSIX_OPEN_MAX, which is of course, the standard " |
|
"symbol. ZVFS_OPEN_MAX may be set by the user. Consider using POSIX_MAX_FDS if the " |
|
"use-case is read-only.", |
|
} |
|
|
|
|
|
def process_file(path): |
|
modified = False |
|
output = [] |
|
|
|
try: |
|
with open(path) as f: |
|
lines = f.readlines() |
|
|
|
lineno = 1 |
|
for line in lines: |
|
longest = "" |
|
length = 0 |
|
for m in REPLACEMENTS: |
|
if re.match(".*" + m + ".*", line) and len(m) > length: |
|
length = len(m) |
|
longest = m |
|
|
|
# TIMER is just way too frequent an occurrence. Skip it. |
|
skip = {"TIMER"} |
|
if length != 0: |
|
if longest in skip: |
|
pass |
|
else: |
|
modified = True |
|
old = line |
|
line = line.replace(longest, REPLACEMENTS[longest]) |
|
msg = MESSAGES.get(longest) |
|
if msg: |
|
print(f"{path}:{lineno}:old:{old.strip()}") |
|
print(f"{path}:{lineno}:new:{line.strip()}") |
|
|
|
lineno += 1 |
|
output.append(line) |
|
|
|
if modified is False or args.dry_run: |
|
return |
|
|
|
with open(path, "w") as f: |
|
f.writelines(output) |
|
|
|
except UnicodeDecodeError: |
|
print(f"Unable to read lines from {path}", file=sys.stderr) |
|
except Exception as e: |
|
print(f"Failed with exception {e}", e) |
|
|
|
|
|
def process_tree(project): |
|
for p in project.glob("**/*"): |
|
for fp in FILE_PATTERNS: |
|
cfp = re.compile(".+/" + fp + "$") |
|
if re.match(cfp, str(p)) is not None: |
|
process_file(p) |
|
|
|
|
|
if __name__ == "__main__": |
|
parser = argparse.ArgumentParser(allow_abbrev=False) |
|
parser.add_argument( |
|
"-r", |
|
"--root", |
|
type=Path, |
|
required=True, |
|
help="Zephyr-based project path") |
|
parser.add_argument( |
|
"-d", |
|
"--dry-run", |
|
action="store_true", |
|
help="log potential changes without modifying files") |
|
args = parser.parse_args() |
|
|
|
process_tree(args.root)
|
|
|