Skip to content

Commit ccd15df

Browse files
Corey Whartonandrewboie
authored andcommitted
scripts: Dynamically add driver subsystems to subsystems list
This change extends the parse_syscalls.py script to scan for a __subsystem sentinal added to driver api declarations. It thens generates a list that is passed into gen_kobject_list.py to extend the subsystems list. This allows subsystems to be declared in the code instead of a separate python list and provides a mechanism for defining out-of-tree subsystems. Signed-off-by: Corey Wharton <[email protected]>
1 parent bedd4e0 commit ccd15df

File tree

5 files changed

+90
-33
lines changed

5 files changed

+90
-33
lines changed

CMakeLists.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -494,6 +494,7 @@ endif()
494494

495495
set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h)
496496
set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json)
497+
set(subsys_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/subsystems.json)
497498

498499
# The syscalls subdirs txt file is constructed by python containing a list of folders to use for
499500
# dependency handling, including empty folders.
@@ -585,12 +586,14 @@ endforeach()
585586
add_custom_command(
586587
OUTPUT
587588
${syscalls_json}
589+
${subsys_json}
588590
COMMAND
589591
${PYTHON_EXECUTABLE}
590592
${ZEPHYR_BASE}/scripts/parse_syscalls.py
591593
--include ${ZEPHYR_BASE}/include # Read files from this dir
592594
${parse_syscalls_include_args} # Read files from these dirs also
593-
--json-file ${syscalls_json} # Write this file
595+
--json-file ${syscalls_json} # Write this file
596+
--subsystem-file ${subsys_json} # Write subsystem list to this file
594597
DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS}
595598
)
596599

@@ -617,15 +620,21 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h}
617620
DEPENDS ${syscalls_json}
618621
)
619622

623+
# This is passed into all calls to the gen_kobject_list.py script.
624+
set(gen_kobject_list_include_args --include ${subsys_json})
625+
620626
set(DRV_VALIDATION ${PROJECT_BINARY_DIR}/include/generated/driver-validation.h)
621627
add_custom_command(
622628
OUTPUT ${DRV_VALIDATION}
623629
COMMAND
624630
${PYTHON_EXECUTABLE}
625631
${ZEPHYR_BASE}/scripts/gen_kobject_list.py
626632
--validation-output ${DRV_VALIDATION}
633+
${gen_kobject_list_include_args}
627634
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
628-
DEPENDS ${ZEPHYR_BASE}/scripts/gen_kobject_list.py
635+
DEPENDS
636+
${ZEPHYR_BASE}/scripts/gen_kobject_list.py
637+
${subsys_json}
629638
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
630639
)
631640
add_custom_target(${DRIVER_VALIDATION_H_TARGET} DEPENDS ${DRV_VALIDATION})
@@ -941,8 +950,11 @@ if(CONFIG_USERSPACE)
941950
${GEN_KOBJ_LIST}
942951
--kernel $<TARGET_FILE:${ZEPHYR_PREBUILT_EXECUTABLE}>
943952
--gperf-output ${OBJ_LIST}
953+
${gen_kobject_list_include_args}
944954
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
945-
DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE}
955+
DEPENDS
956+
${ZEPHYR_PREBUILT_EXECUTABLE}
957+
${subsys_json}
946958
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
947959
)
948960
add_custom_target(obj_list DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OBJ_LIST})

cmake/kobj.cmake

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ function(gen_kobj gen_dir_out)
2121
--kobj-types-output ${KOBJ_TYPES}
2222
--kobj-otype-output ${KOBJ_OTYPE}
2323
--kobj-size-output ${KOBJ_SIZE}
24+
${gen_kobject_list_include_args}
2425
$<$<BOOL:${CMAKE_VERBOSE_MAKEFILE}>:--verbose>
25-
DEPENDS $ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py
26+
DEPENDS
27+
$ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py
28+
${subsys_json}
2629
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
2730
)
2831
add_custom_target(${KOBJ_TYPES_H_TARGET} DEPENDS ${KOBJ_TYPES} ${KOBJ_OTYPE})

include/toolchain/common.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@
132132
#define __syscall
133133
#endif /* #ifndef ZTEST_UNITTEST */
134134

135+
/* Used as a sentinel by parse_syscalls.py to identify what API structs
136+
* define driver subsystems.
137+
*/
138+
#define __subsystem
139+
135140
#ifndef BUILD_ASSERT
136141
/* compile-time assertion that makes the build fail */
137142
#define BUILD_ASSERT(EXPR) \

scripts/gen_kobject_list.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import math
5757
import os
5858
import struct
59+
import json
5960
from elf_helper import ElfHelper, kobject_to_enum
6061

6162
from collections import OrderedDict
@@ -90,8 +91,6 @@
9091
("k_futex", (None, True))
9192
])
9293

93-
94-
9594
subsystems = [
9695
"adc_driver_api",
9796
"aio_cmp_driver_api",
@@ -331,6 +330,11 @@ def write_kobj_size_output(fp):
331330
fp.write("#endif\n")
332331

333332

333+
def parse_subsystems_list_file(path):
334+
with open(path, "r") as fp:
335+
subsys_list = json.load(fp)
336+
subsystems.extend(subsys_list)
337+
334338
def parse_args():
335339
global args
336340

@@ -355,6 +359,11 @@ def parse_args():
355359
parser.add_argument(
356360
"-Z", "--kobj-size-output", required=False,
357361
help="Output case statements for obj_size_get()")
362+
parser.add_argument("-i", "--include-subsystem-list", required=False, action='append',
363+
help='''Specifies a file with a JSON encoded list of subsystem names to append to
364+
the driver subsystems list. Can be specified multiple times:
365+
-i file1 -i file2 ...''')
366+
358367
parser.add_argument("-v", "--verbose", action="store_true",
359368
help="Print extra debugging information")
360369
args = parser.parse_args()
@@ -365,6 +374,10 @@ def parse_args():
365374
def main():
366375
parse_args()
367376

377+
if args.include_subsystem_list is not None:
378+
for list_file in args.include_subsystem_list:
379+
parse_subsystems_list_file(list_file)
380+
368381
if args.gperf_output:
369382
assert args.kernel, "--kernel ELF required for --gperf-output"
370383
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems)

scripts/parse_syscalls.py

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# SPDX-License-Identifier: Apache-2.0
66

77
"""
8-
Script to scan Zephyr include directories and emit system call metadata
8+
Script to scan Zephyr include directories and emit system call and subsystem metadata
99
1010
System calls require a great deal of boilerplate code in order to implement
1111
completely. This script is the first step in the build system's process of
@@ -26,41 +26,66 @@
2626
import os
2727
import json
2828

29-
api_regex = re.compile(r'''
29+
syscall_regex = re.compile(r'''
3030
__syscall\s+ # __syscall attribute, must be first
3131
([^(]+) # type and name of system call (split later)
3232
[(] # Function opening parenthesis
3333
([^)]*) # Arg list (split later)
3434
[)] # Closing parenthesis
3535
''', re.MULTILINE | re.VERBOSE)
3636

37+
subsys_regex = re.compile(r'''
38+
__subsystem\s+ # __subsystem attribute, must be first
39+
struct\s+ # struct keyword is next
40+
([^{]+) # name of subsystem
41+
[{] # Open curly bracket
42+
''', re.MULTILINE | re.VERBOSE)
3743

3844
def analyze_headers(multiple_directories):
39-
ret = []
45+
syscall_ret = []
46+
subsys_ret = []
4047

4148
for base_path in multiple_directories:
4249
for root, dirs, files in os.walk(base_path, topdown=True):
4350
dirs.sort()
4451
files.sort()
4552
for fn in files:
4653

47-
# toolchain/common.h has the definition of __syscall which we
54+
# toolchain/common.h has the definitions of __syscall and __subsystem which we
4855
# don't want to trip over
4956
path = os.path.join(root, fn)
5057
if not fn.endswith(".h") or path.endswith(os.path.join(os.sep, 'toolchain', 'common.h')):
5158
continue
5259

5360
with open(path, "r", encoding="utf-8") as fp:
54-
try:
55-
result = [(mo.groups(), fn)
56-
for mo in api_regex.finditer(fp.read())]
57-
except Exception:
58-
sys.stderr.write("While parsing %s\n" % fn)
59-
raise
61+
contents = fp.read()
62+
63+
try:
64+
syscall_result = [(mo.groups(), fn)
65+
for mo in syscall_regex.finditer(contents)]
66+
subsys_result = [mo.groups()[0].strip()
67+
for mo in subsys_regex.finditer(contents)]
68+
except Exception:
69+
sys.stderr.write("While parsing %s\n" % fn)
70+
raise
6071

61-
ret.extend(result)
72+
syscall_ret.extend(syscall_result)
73+
subsys_ret.extend(subsys_result)
6274

63-
return ret
75+
return syscall_ret, subsys_ret
76+
77+
78+
def update_file_if_changed(path, new):
79+
if os.path.exists(path):
80+
with open(path, 'r') as fp:
81+
old = fp.read()
82+
83+
if new != old:
84+
with open(path, 'w') as fp:
85+
fp.write(new)
86+
else:
87+
with open(path, 'w') as fp:
88+
fp.write(new)
6489

6590

6691
def parse_args():
@@ -76,34 +101,33 @@ def parse_args():
76101
parser.add_argument(
77102
"-j", "--json-file", required=True,
78103
help="Write system call prototype information as json to file")
104+
parser.add_argument(
105+
"-s", "--subsystem-file", required=True,
106+
help="Write subsystem name information as json to file")
79107
args = parser.parse_args()
80108

81109

82110
def main():
83111
parse_args()
84112

85-
syscalls = analyze_headers(args.include)
113+
syscalls, subsys = analyze_headers(args.include)
114+
115+
# Only write json files if they don't exist or have changes since
116+
# they will force and incremental rebuild.
86117

87118
syscalls_in_json = json.dumps(
88119
syscalls,
89120
indent=4,
90121
sort_keys=True
91122
)
123+
update_file_if_changed(args.json_file, syscalls_in_json)
92124

93-
# Check if the file already exists, and if there are no changes,
94-
# don't touch it since that will force an incremental rebuild
95-
path = args.json_file
96-
new = syscalls_in_json
97-
if os.path.exists(path):
98-
with open(path, 'r') as fp:
99-
old = fp.read()
100-
101-
if new != old:
102-
with open(path, 'w') as fp:
103-
fp.write(new)
104-
else:
105-
with open(path, 'w') as fp:
106-
fp.write(new)
125+
subsys_in_json = json.dumps(
126+
subsys,
127+
indent=4,
128+
sort_keys=True
129+
)
130+
update_file_if_changed(args.subsystem_file, subsys_in_json)
107131

108132

109133
if __name__ == "__main__":

0 commit comments

Comments
 (0)