xref: /llvm-project/libcxx/utils/sym_diff.py (revision 7bfaa0f09d0564f315ea778023b34b8a113ec740)
1#!/usr/bin/env python
2# ===----------------------------------------------------------------------===##
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#
8# ===----------------------------------------------------------------------===##
9"""
10sym_diff - Compare two symbol lists and output the differences.
11"""
12
13from argparse import ArgumentParser
14import sys
15from libcxx.sym_check import diff, util
16
17
18def main():
19    parser = ArgumentParser(
20        description="Extract a list of symbols from a shared library."
21    )
22    parser.add_argument(
23        "--names-only",
24        dest="names_only",
25        help="Only print symbol names",
26        action="store_true",
27        default=False,
28    )
29    parser.add_argument(
30        "--removed-only",
31        dest="removed_only",
32        help="Only print removed symbols",
33        action="store_true",
34        default=False,
35    )
36    parser.add_argument(
37        "--only-stdlib-symbols",
38        dest="only_stdlib",
39        help="Filter all symbols not related to the stdlib",
40        action="store_true",
41        default=False,
42    )
43    parser.add_argument(
44        "--strict",
45        dest="strict",
46        help="Exit with a non-zero status if any symbols " "differ",
47        action="store_true",
48        default=False,
49    )
50    parser.add_argument(
51        "-o",
52        "--output",
53        dest="output",
54        help="The output file. stdout is used if not given",
55        type=str,
56        action="store",
57        default=None,
58    )
59    parser.add_argument(
60        "--demangle", dest="demangle", action="store_true", default=False
61    )
62    parser.add_argument(
63        "old_syms",
64        metavar="old-syms",
65        type=str,
66        help="The file containing the old symbol list or a library",
67    )
68    parser.add_argument(
69        "new_syms",
70        metavar="new-syms",
71        type=str,
72        help="The file containing the new symbol list or a library",
73    )
74    args = parser.parse_args()
75
76    old_syms_list = util.extract_or_load(args.old_syms)
77    new_syms_list = util.extract_or_load(args.new_syms)
78
79    if args.only_stdlib:
80        old_syms_list, _ = util.filter_stdlib_symbols(old_syms_list)
81        new_syms_list, _ = util.filter_stdlib_symbols(new_syms_list)
82
83    added, removed, changed = diff.diff(old_syms_list, new_syms_list)
84    if args.removed_only:
85        added = {}
86    report, is_break, is_different = diff.report_diff(
87        added, removed, changed, names_only=args.names_only, demangle=args.demangle
88    )
89    if args.output is None:
90        print(report)
91    else:
92        with open(args.output, "w") as f:
93            f.write(report + "\n")
94    exit_code = 1 if is_break or (args.strict and is_different) else 0
95    sys.exit(exit_code)
96
97
98if __name__ == "__main__":
99    main()
100