-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathswift-abi-symbol-checker.py
executable file
·94 lines (64 loc) · 3.03 KB
/
swift-abi-symbol-checker.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#!/usr/bin/env python3
import argparse
import sys
def getAdditionsAndRemovals(changesFile):
changesF = open(changesFile)
changes = changesF.read()
changesF.close()
# Get rid of lines that start with either '//' or a newline
changes = [c for c in changes.splitlines() if not c.startswith('//') and c != '']
# Filter the changes for lines that start with Added
additions = [a for a in changes if a.startswith('Added')]
# Filter the changes for lines that start with Removed
removals = [r for r in changes if r.startswith('Removed')]
# Map the additions by removing the 'Added: ' prefix to get just the symbol
additions = list(map(lambda a: a.removeprefix('Added: '), additions))
# Map the removals by removing the 'Removed: ' prefix to get just the symbol
removals = list(map(lambda r: r.removeprefix('Removed: '), removals))
return (additions, removals)
def checkSymbols(args):
# If we were passed a base file, read those changes first. This most likely
# occurs in assert configurations getting the non-assert base.
baseAdditions = []
baseRemovals = []
if args.base:
(baseAdditions, baseRemovals) = getAdditionsAndRemovals(args.base)
(additions, removals) = getAdditionsAndRemovals(args.changes)
# Append the base additions and removals to ours.
additions.extend(baseAdditions)
removals.extend(baseRemovals)
# We need to write back to the temporary symbol file for diffing
symbolsF = open(args.symbols, 'r+')
symbols = symbolsF.read().splitlines()
# Check for added symbols that are not actually in the just built dylib.
notInDylib = [a for a in additions if a not in symbols]
# If there were symbols marked as 'Added' in the changes file, but they didn't
# actually appear in the dylib then print those symbols out and fail.
if notInDylib:
for symbol in notInDylib:
symbols.append('<MISSING ADDITION> {}'.format(symbol))
# Filter the built symbols for the additions because we're removing them to
# get back to the baseline
symbols = [s for s in symbols if s not in additions]
# Append the removals into the symbol list to get back to the baseline
symbols.extend(removals)
# Sort the end result to write back
symbols.sort()
# Go back to beginning of the file and purge everything
symbolsF.seek(0)
symbolsF.truncate()
# Append a newline to each symbol (because writelines doesn't do that for us)
symbols = list(map(lambda s: s + '\n', symbols))
# Write all of our symbols back into the symbols file
symbolsF.writelines(symbols)
# Done
symbolsF.close()
def main(arguments):
parser = argparse.ArgumentParser(
description='Change absolute install names to use @rpath')
parser.add_argument('changes', help='the changes file')
parser.add_argument('symbols', help='the symbols file')
parser.add_argument('--base', help='the base changes file')
args = parser.parse_args(arguments)
checkSymbols(args)
sys.exit(main(sys.argv[1:]))