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