blob: e00474fe71b618d1b6fa7289c08e0e610647365c [file] [log] [blame]
Sebastian Bøe13a68402017-11-20 13:03:55 +01001#!/usr/bin/env python3
2#
3# Copyright (c) 2017 Intel Corporation
4#
5# SPDX-License-Identifier: Apache-2.0
6
Andrew Boiec78c5e62019-03-11 14:45:43 -07007"""
Corey Whartonccd15df2020-02-29 14:51:42 -08008Script to scan Zephyr include directories and emit system call and subsystem metadata
Andrew Boiec78c5e62019-03-11 14:45:43 -07009
10System calls require a great deal of boilerplate code in order to implement
11completely. This script is the first step in the build system's process of
12auto-generating this code by doing a text scan of directories containing
Andrew Boie59601192020-05-29 13:24:51 -070013C or header files, and building up a database of system calls and their
Andrew Boiec78c5e62019-03-11 14:45:43 -070014function call prototypes. This information is emitted to a generated
15JSON file for further processing.
16
Andrew Boie59601192020-05-29 13:24:51 -070017This script also scans for struct definitions such as __subsystem and
18__net_socket, emitting a JSON dictionary mapping tags to all the struct
19declarations found that were tagged with them.
20
Andrew Boiec78c5e62019-03-11 14:45:43 -070021If the output JSON file already exists, its contents are checked against
22what information this script would have outputted; if the result is that the
23file would be unchanged, it is not modified to prevent unnecessary
24incremental builds.
25"""
26
Sebastian Bøe13a68402017-11-20 13:03:55 +010027import sys
28import re
29import argparse
30import os
31import json
32
Andrew Boie59601192020-05-29 13:24:51 -070033regex_flags = re.MULTILINE | re.VERBOSE
34
Corey Whartonccd15df2020-02-29 14:51:42 -080035syscall_regex = re.compile(r'''
Sebastian Bøe13a68402017-11-20 13:03:55 +010036__syscall\s+ # __syscall attribute, must be first
37([^(]+) # type and name of system call (split later)
38[(] # Function opening parenthesis
39([^)]*) # Arg list (split later)
40[)] # Closing parenthesis
Andrew Boie59601192020-05-29 13:24:51 -070041''', regex_flags)
Sebastian Bøe13a68402017-11-20 13:03:55 +010042
Andrew Boie299ec8f2020-05-29 13:30:19 -070043struct_tags = ["__subsystem", "__net_socket"]
Andrew Boie59601192020-05-29 13:24:51 -070044
45tagged_struct_decl_template = r'''
46%s\s+ # tag, must be first
Corey Whartonccd15df2020-02-29 14:51:42 -080047struct\s+ # struct keyword is next
48([^{]+) # name of subsystem
49[{] # Open curly bracket
Andrew Boie59601192020-05-29 13:24:51 -070050'''
51
52def tagged_struct_update(target_list, tag, contents):
53 regex = re.compile(tagged_struct_decl_template % tag, regex_flags)
54 items = [mo.groups()[0].strip() for mo in regex.finditer(contents)]
55 target_list.extend(items)
56
Sebastian Bøe13a68402017-11-20 13:03:55 +010057
Adithya Baglodye67720b2018-07-02 14:59:19 +053058def analyze_headers(multiple_directories):
Corey Whartonccd15df2020-02-29 14:51:42 -080059 syscall_ret = []
Andrew Boie59601192020-05-29 13:24:51 -070060 tagged_ret = {}
61
62 for tag in struct_tags:
63 tagged_ret[tag] = []
Sebastian Bøe13a68402017-11-20 13:03:55 +010064
Adithya Baglodye67720b2018-07-02 14:59:19 +053065 for base_path in multiple_directories:
Marc Herbertd5b28342019-02-15 18:56:57 -080066 for root, dirs, files in os.walk(base_path, topdown=True):
67 dirs.sort()
68 files.sort()
Adithya Baglodye67720b2018-07-02 14:59:19 +053069 for fn in files:
Sebastian Bøe13a68402017-11-20 13:03:55 +010070
Andrew Boie59601192020-05-29 13:24:51 -070071 # toolchain/common.h has the definitions of these tagswhich we
Adithya Baglodye67720b2018-07-02 14:59:19 +053072 # don't want to trip over
73 path = os.path.join(root, fn)
Andrew Boie59601192020-05-29 13:24:51 -070074 if (not (path.endswith(".h") or path.endswith(".c")) or
75 path.endswith(os.path.join(os.sep, 'toolchain',
76 'common.h'))):
Adithya Baglodye67720b2018-07-02 14:59:19 +053077 continue
Sebastian Bøe13a68402017-11-20 13:03:55 +010078
Adithya Baglodye67720b2018-07-02 14:59:19 +053079 with open(path, "r", encoding="utf-8") as fp:
Corey Whartonccd15df2020-02-29 14:51:42 -080080 contents = fp.read()
Sebastian Bøe13a68402017-11-20 13:03:55 +010081
Corey Whartonccd15df2020-02-29 14:51:42 -080082 try:
83 syscall_result = [(mo.groups(), fn)
84 for mo in syscall_regex.finditer(contents)]
Andrew Boie59601192020-05-29 13:24:51 -070085 for tag in struct_tags:
86 tagged_struct_update(tagged_ret[tag], tag, contents)
Corey Whartonccd15df2020-02-29 14:51:42 -080087 except Exception:
88 sys.stderr.write("While parsing %s\n" % fn)
89 raise
Sebastian Bøe13a68402017-11-20 13:03:55 +010090
Corey Whartonccd15df2020-02-29 14:51:42 -080091 syscall_ret.extend(syscall_result)
Corey Whartonccd15df2020-02-29 14:51:42 -080092
Andrew Boie59601192020-05-29 13:24:51 -070093 return syscall_ret, tagged_ret
Corey Whartonccd15df2020-02-29 14:51:42 -080094
95
96def update_file_if_changed(path, new):
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)
Sebastian Bøe13a68402017-11-20 13:03:55 +0100107
Anas Nashif72565532017-12-12 08:19:25 -0500108
Sebastian Bøe13a68402017-11-20 13:03:55 +0100109def parse_args():
110 global args
Anas Nashif72565532017-12-12 08:19:25 -0500111 parser = argparse.ArgumentParser(
112 description=__doc__,
113 formatter_class=argparse.RawDescriptionHelpFormatter)
Sebastian Bøe13a68402017-11-20 13:03:55 +0100114
Adithya Baglodye67720b2018-07-02 14:59:19 +0530115 parser.add_argument("-i", "--include", required=True, action='append',
Marc Herbertd5b28342019-02-15 18:56:57 -0800116 help='''include directories recursively scanned
117 for .h files. Can be specified multiple times:
118 -i topdir1 -i topdir2 ...''')
Anas Nashif72565532017-12-12 08:19:25 -0500119 parser.add_argument(
120 "-j", "--json-file", required=True,
121 help="Write system call prototype information as json to file")
Corey Whartonccd15df2020-02-29 14:51:42 -0800122 parser.add_argument(
Andrew Boie59601192020-05-29 13:24:51 -0700123 "-t", "--tag-struct-file", required=True,
124 help="Write tagged struct name information as json to file")
125
Sebastian Bøe13a68402017-11-20 13:03:55 +0100126 args = parser.parse_args()
127
Anas Nashif72565532017-12-12 08:19:25 -0500128
Sebastian Bøe13a68402017-11-20 13:03:55 +0100129def main():
130 parse_args()
131
Andrew Boie59601192020-05-29 13:24:51 -0700132 syscalls, tagged = analyze_headers(args.include)
Corey Whartonccd15df2020-02-29 14:51:42 -0800133
134 # Only write json files if they don't exist or have changes since
Andrew Boie59601192020-05-29 13:24:51 -0700135 # they will force an incremental rebuild.
Sebastian Bøe13a68402017-11-20 13:03:55 +0100136
137 syscalls_in_json = json.dumps(
138 syscalls,
139 indent=4,
140 sort_keys=True
141 )
Corey Whartonccd15df2020-02-29 14:51:42 -0800142 update_file_if_changed(args.json_file, syscalls_in_json)
Sebastian Bøe13a68402017-11-20 13:03:55 +0100143
Andrew Boie59601192020-05-29 13:24:51 -0700144 tagged_struct_in_json = json.dumps(
145 tagged,
Corey Whartonccd15df2020-02-29 14:51:42 -0800146 indent=4,
147 sort_keys=True
148 )
Andrew Boie59601192020-05-29 13:24:51 -0700149 update_file_if_changed(args.tag_struct_file, tagged_struct_in_json)
Sebastian Bøe13a68402017-11-20 13:03:55 +0100150
Anas Nashif72565532017-12-12 08:19:25 -0500151
Sebastian Bøe13a68402017-11-20 13:03:55 +0100152if __name__ == "__main__":
153 main()