xref: /dpdk/devtools/update_version_map_abi.py (revision 56ea803e878e06ac1c7056165b960416666086f4)
13f6f8362SLouise Kilheeney#!/usr/bin/env python3
2b09afc2aSDavid Marchand# SPDX-License-Identifier: BSD-3-Clause
3b09afc2aSDavid Marchand# Copyright(c) 2019 Intel Corporation
4b09afc2aSDavid Marchand
5b09afc2aSDavid Marchand"""
6b09afc2aSDavid MarchandA Python program that updates and merges all available stable ABI versions into
7b09afc2aSDavid Marchandone ABI version, while leaving experimental ABI exactly as it is. The intended
8b09afc2aSDavid MarchandABI version is supplied via command-line parameter. This script is to be called
9b09afc2aSDavid Marchandfrom the devtools/update-abi.sh utility.
10b09afc2aSDavid Marchand"""
11b09afc2aSDavid Marchand
12b09afc2aSDavid Marchandimport argparse
13b09afc2aSDavid Marchandimport sys
14b09afc2aSDavid Marchandimport re
15b09afc2aSDavid Marchand
16b09afc2aSDavid Marchand
17b09afc2aSDavid Marchanddef __parse_map_file(f_in):
18*56ea803eSDavid Marchand    # match function name, followed by semicolon, followed by EOL or comments,
19*56ea803eSDavid Marchand    # optionally with whitespace in between each item
20b09afc2aSDavid Marchand    func_line_regex = re.compile(r"\s*"
21*56ea803eSDavid Marchand                                 r"(?P<line>"
22b09afc2aSDavid Marchand                                 r"(?P<func>[a-zA-Z_0-9]+)"
23b09afc2aSDavid Marchand                                 r"\s*"
24b09afc2aSDavid Marchand                                 r";"
25b09afc2aSDavid Marchand                                 r"\s*"
26*56ea803eSDavid Marchand                                 r"(?P<comment>#.+)?"
27*56ea803eSDavid Marchand                                 r")"
28*56ea803eSDavid Marchand                                 r"\s*"
29b09afc2aSDavid Marchand                                 r"$")
30b09afc2aSDavid Marchand    # match section name, followed by opening bracked, followed by EOL,
31b09afc2aSDavid Marchand    # optionally with whitespace in between each item
32b09afc2aSDavid Marchand    section_begin_regex = re.compile(r"\s*"
33b09afc2aSDavid Marchand                                     r"(?P<version>[a-zA-Z0-9_\.]+)"
34b09afc2aSDavid Marchand                                     r"\s*"
35b09afc2aSDavid Marchand                                     r"{"
36b09afc2aSDavid Marchand                                     r"\s*"
37b09afc2aSDavid Marchand                                     r"$")
38b09afc2aSDavid Marchand    # match closing bracket, optionally followed by section name (for when we
39b09afc2aSDavid Marchand    # inherit from another ABI version), followed by semicolon, followed by
40b09afc2aSDavid Marchand    # EOL, optionally with whitespace in between each item
41b09afc2aSDavid Marchand    section_end_regex = re.compile(r"\s*"
42b09afc2aSDavid Marchand                                   r"}"
43b09afc2aSDavid Marchand                                   r"\s*"
44b09afc2aSDavid Marchand                                   r"(?P<parent>[a-zA-Z0-9_\.]+)?"
45b09afc2aSDavid Marchand                                   r"\s*"
46b09afc2aSDavid Marchand                                   r";"
47b09afc2aSDavid Marchand                                   r"\s*"
48b09afc2aSDavid Marchand                                   r"$")
49b09afc2aSDavid Marchand
50b09afc2aSDavid Marchand    # for stable ABI, we don't care about which version introduced which
51b09afc2aSDavid Marchand    # function, we just flatten the list. there are dupes in certain files, so
52b09afc2aSDavid Marchand    # use a set instead of a list
53b09afc2aSDavid Marchand    stable_lines = set()
54b09afc2aSDavid Marchand    # copy experimental section as is
55b09afc2aSDavid Marchand    experimental_lines = []
56c2403cd7SHaiyue Wang    # copy internal section as is
57c2403cd7SHaiyue Wang    internal_lines = []
58b09afc2aSDavid Marchand    in_experimental = False
59c2403cd7SHaiyue Wang    in_internal = False
60b09afc2aSDavid Marchand    has_stable = False
61b09afc2aSDavid Marchand
62b09afc2aSDavid Marchand    # gather all functions
63b09afc2aSDavid Marchand    for line in f_in:
64b09afc2aSDavid Marchand        # clean up the line
65b09afc2aSDavid Marchand        line = line.strip('\n').strip()
66b09afc2aSDavid Marchand
67b09afc2aSDavid Marchand        # is this an end of section?
68b09afc2aSDavid Marchand        match = section_end_regex.match(line)
69b09afc2aSDavid Marchand        if match:
70b09afc2aSDavid Marchand            # whatever section this was, it's not active any more
71b09afc2aSDavid Marchand            in_experimental = False
72c2403cd7SHaiyue Wang            in_internal = False
73b09afc2aSDavid Marchand            continue
74b09afc2aSDavid Marchand
75b09afc2aSDavid Marchand        # if we're in the middle of experimental section, we need to copy
76b09afc2aSDavid Marchand        # the section verbatim, so just add the line
77b09afc2aSDavid Marchand        if in_experimental:
78b09afc2aSDavid Marchand            experimental_lines += [line]
79b09afc2aSDavid Marchand            continue
80b09afc2aSDavid Marchand
81c2403cd7SHaiyue Wang        # if we're in the middle of internal section, we need to copy
82c2403cd7SHaiyue Wang        # the section verbatim, so just add the line
83c2403cd7SHaiyue Wang        if in_internal:
84c2403cd7SHaiyue Wang            internal_lines += [line]
85c2403cd7SHaiyue Wang            continue
86c2403cd7SHaiyue Wang
87b09afc2aSDavid Marchand        # skip empty lines
88b09afc2aSDavid Marchand        if not line:
89b09afc2aSDavid Marchand            continue
90b09afc2aSDavid Marchand
91b09afc2aSDavid Marchand        # is this a beginning of a new section?
92b09afc2aSDavid Marchand        match = section_begin_regex.match(line)
93b09afc2aSDavid Marchand        if match:
94b09afc2aSDavid Marchand            cur_section = match.group("version")
95b09afc2aSDavid Marchand            # is it experimental?
96b09afc2aSDavid Marchand            in_experimental = cur_section == "EXPERIMENTAL"
97c2403cd7SHaiyue Wang            # is it internal?
98c2403cd7SHaiyue Wang            in_internal = cur_section == "INTERNAL"
99c2403cd7SHaiyue Wang            if not in_experimental and not in_internal:
100b09afc2aSDavid Marchand                has_stable = True
101b09afc2aSDavid Marchand            continue
102b09afc2aSDavid Marchand
103b09afc2aSDavid Marchand        # is this a function?
104b09afc2aSDavid Marchand        match = func_line_regex.match(line)
105b09afc2aSDavid Marchand        if match:
106*56ea803eSDavid Marchand            stable_lines.add(match.group("line"))
107b09afc2aSDavid Marchand
108c2403cd7SHaiyue Wang    return has_stable, stable_lines, experimental_lines, internal_lines
109b09afc2aSDavid Marchand
110b09afc2aSDavid Marchand
111a6fc38f3SThomas Monjalondef __generate_stable_abi(f_out, abi_major, lines):
112b09afc2aSDavid Marchand    # print ABI version header
113a6fc38f3SThomas Monjalon    print("DPDK_{} {{".format(abi_major), file=f_out)
114b09afc2aSDavid Marchand
115b09afc2aSDavid Marchand    # print global section if it exists
116b09afc2aSDavid Marchand    if lines:
117b09afc2aSDavid Marchand        print("\tglobal:", file=f_out)
118b09afc2aSDavid Marchand        # blank line
119b09afc2aSDavid Marchand        print(file=f_out)
120b09afc2aSDavid Marchand
121b09afc2aSDavid Marchand        # print all stable lines, alphabetically sorted
122b09afc2aSDavid Marchand        for line in sorted(lines):
123*56ea803eSDavid Marchand            print("\t{}".format(line), file=f_out)
124b09afc2aSDavid Marchand
125b09afc2aSDavid Marchand        # another blank line
126b09afc2aSDavid Marchand        print(file=f_out)
127b09afc2aSDavid Marchand
128b09afc2aSDavid Marchand    # print local section
129b09afc2aSDavid Marchand    print("\tlocal: *;", file=f_out)
130b09afc2aSDavid Marchand
131b09afc2aSDavid Marchand    # end stable version
132b09afc2aSDavid Marchand    print("};", file=f_out)
133b09afc2aSDavid Marchand
134b09afc2aSDavid Marchand
135b09afc2aSDavid Marchanddef __generate_experimental_abi(f_out, lines):
136b09afc2aSDavid Marchand    # start experimental section
137b09afc2aSDavid Marchand    print("EXPERIMENTAL {", file=f_out)
138b09afc2aSDavid Marchand
139b09afc2aSDavid Marchand    # print all experimental lines as they were
140b09afc2aSDavid Marchand    for line in lines:
141b09afc2aSDavid Marchand        # don't print empty whitespace
142b09afc2aSDavid Marchand        if not line:
143b09afc2aSDavid Marchand            print("", file=f_out)
144b09afc2aSDavid Marchand        else:
145b09afc2aSDavid Marchand            print("\t{}".format(line), file=f_out)
146b09afc2aSDavid Marchand
147b09afc2aSDavid Marchand    # end section
148b09afc2aSDavid Marchand    print("};", file=f_out)
149b09afc2aSDavid Marchand
150c2403cd7SHaiyue Wangdef __generate_internal_abi(f_out, lines):
151c2403cd7SHaiyue Wang    # start internal section
152c2403cd7SHaiyue Wang    print("INTERNAL {", file=f_out)
153c2403cd7SHaiyue Wang
154c2403cd7SHaiyue Wang    # print all internal lines as they were
155c2403cd7SHaiyue Wang    for line in lines:
156c2403cd7SHaiyue Wang        # don't print empty whitespace
157c2403cd7SHaiyue Wang        if not line:
158c2403cd7SHaiyue Wang            print("", file=f_out)
159c2403cd7SHaiyue Wang        else:
160c2403cd7SHaiyue Wang            print("\t{}".format(line), file=f_out)
161c2403cd7SHaiyue Wang
162c2403cd7SHaiyue Wang    # end section
163c2403cd7SHaiyue Wang    print("};", file=f_out)
164b09afc2aSDavid Marchand
165b09afc2aSDavid Marchanddef __main():
166b09afc2aSDavid Marchand    arg_parser = argparse.ArgumentParser(
167b09afc2aSDavid Marchand        description='Merge versions in linker version script.')
168b09afc2aSDavid Marchand
169b09afc2aSDavid Marchand    arg_parser.add_argument("map_file", type=str,
170b09afc2aSDavid Marchand                            help='path to linker version script file '
171a8d0d473SBruce Richardson                                 '(pattern: version.map)')
172b09afc2aSDavid Marchand    arg_parser.add_argument("abi_version", type=str,
173b09afc2aSDavid Marchand                            help='target ABI version (pattern: MAJOR.MINOR)')
174b09afc2aSDavid Marchand
175b09afc2aSDavid Marchand    parsed = arg_parser.parse_args()
176b09afc2aSDavid Marchand
177b09afc2aSDavid Marchand    if not parsed.map_file.endswith('version.map'):
178b09afc2aSDavid Marchand        print("Invalid input file: {}".format(parsed.map_file),
179b09afc2aSDavid Marchand              file=sys.stderr)
180b09afc2aSDavid Marchand        arg_parser.print_help()
181b09afc2aSDavid Marchand        sys.exit(1)
182b09afc2aSDavid Marchand
183b09afc2aSDavid Marchand    if not re.match(r"\d{1,2}\.\d{1,2}", parsed.abi_version):
184b09afc2aSDavid Marchand        print("Invalid ABI version: {}".format(parsed.abi_version),
185b09afc2aSDavid Marchand              file=sys.stderr)
186b09afc2aSDavid Marchand        arg_parser.print_help()
187b09afc2aSDavid Marchand        sys.exit(1)
188a6fc38f3SThomas Monjalon    abi_major = parsed.abi_version.split('.')[0]
189b09afc2aSDavid Marchand
190b09afc2aSDavid Marchand    with open(parsed.map_file) as f_in:
191c2403cd7SHaiyue Wang        has_stable, stable_lines, experimental_lines, internal_lines = __parse_map_file(f_in)
192b09afc2aSDavid Marchand
193b09afc2aSDavid Marchand    with open(parsed.map_file, 'w') as f_out:
194b09afc2aSDavid Marchand        need_newline = has_stable and experimental_lines
195b09afc2aSDavid Marchand        if has_stable:
196a6fc38f3SThomas Monjalon            __generate_stable_abi(f_out, abi_major, stable_lines)
197b09afc2aSDavid Marchand        if need_newline:
198b09afc2aSDavid Marchand            # separate sections with a newline
199b09afc2aSDavid Marchand            print(file=f_out)
200b09afc2aSDavid Marchand        if experimental_lines:
201b09afc2aSDavid Marchand            __generate_experimental_abi(f_out, experimental_lines)
202c2403cd7SHaiyue Wang        if internal_lines:
203c2403cd7SHaiyue Wang            if has_stable or experimental_lines:
204c2403cd7SHaiyue Wang              # separate sections with a newline
205c2403cd7SHaiyue Wang              print(file=f_out)
206c2403cd7SHaiyue Wang            __generate_internal_abi(f_out, internal_lines)
207b09afc2aSDavid Marchand
208b09afc2aSDavid Marchand
209b09afc2aSDavid Marchandif __name__ == "__main__":
210b09afc2aSDavid Marchand    __main()
211