Skip to content

Commit bf102d2

Browse files
authored
Merge pull request #69765 from Azoy/abi-checker-but-for-real
[ABI] Introduce an ABI checker that diffs symbols
2 parents d270dad + 7dd52a2 commit bf102d2

File tree

10 files changed

+55721
-0
lines changed

10 files changed

+55721
-0
lines changed

test/abi/Inputs/macOS/arm64/stdlib/baseline

Lines changed: 13882 additions & 0 deletions
Large diffs are not rendered by default.

test/abi/Inputs/macOS/arm64/stdlib/baseline-asserts

Lines changed: 13978 additions & 0 deletions
Large diffs are not rendered by default.

test/abi/Inputs/macOS/x86_64/stdlib/baseline

Lines changed: 13741 additions & 0 deletions
Large diffs are not rendered by default.

test/abi/Inputs/macOS/x86_64/stdlib/baseline-asserts

Lines changed: 13837 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %llvm-nm -g --defined-only -f just-symbols %stdlib_dir/arm64/libswiftCore.dylib > %t/symbols
3+
// RUN: %abi-symbol-checker %s %t/symbols --base %S/stdlib.swift
4+
// RUN: diff -u %S/../../Inputs/macOS/arm64/stdlib/baseline-asserts %t/symbols
5+
6+
// REQUIRES: swift_stdlib_asserts
7+
// REQUIRES: STDLIB_VARIANT=macosx-arm64
8+
9+
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment below.)
10+
11+
// Welcome, Build Wrangler!
12+
//
13+
// This file lists APIs that have recently changed in a way that potentially
14+
// indicates an ABI- or source-breaking problem.
15+
//
16+
// A failure in this test indicates that there is a potential breaking change in
17+
// the Standard Library. If you observe a failure outside of a PR test, please
18+
// reach out to the Standard Library team directly to make sure this gets
19+
// resolved quickly! If your own PR fails in this test, you probably have an
20+
// ABI- or source-breaking change in your commits. Please go and fix it.
21+
//
22+
// Please DO NOT DISABLE THIS TEST. In addition to ignoring the current set of
23+
// ABI breaks, XFAILing this test also silences any future ABI breaks that may
24+
// land on this branch, which simply generates extra work for the next person
25+
// that picks up the mess.
26+
//
27+
// Instead of disabling this test, you'll need to extend the list of expected
28+
// changes at the bottom. (You'll also need to do this if your own PR triggers
29+
// false positives, or if you have special permission to break things.) You can
30+
// find a diff of what needs to be added in the output of the failed test run.
31+
// The order of lines doesn't matter, and you can also include comments to refer
32+
// to any bugs you filed.
33+
//
34+
// Thank you for your help ensuring the stdlib remains compatible with its past!
35+
// -- Your friendly stdlib engineers
36+
37+
// *** NOTE: ***
38+
// You will normally add new entries in 'abi/macOS/arm64/stdlib.swift' instead
39+
// of this file. This file is dedicated for assert only symbols.
40+
41+
// Standard Library Symbols
42+
43+
// Runtime Symbols

test/abi/macOS/arm64/stdlib.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %llvm-nm -g --defined-only -f just-symbols %stdlib_dir/arm64/libswiftCore.dylib > %t/symbols
3+
// RUN: %abi-symbol-checker %s %t/symbols
4+
// RUN: diff -u %S/../../Inputs/macOS/arm64/stdlib/baseline %t/symbols
5+
6+
// REQUIRES: swift_stdlib_no_asserts
7+
// REQUIRES: STDLIB_VARIANT=macosx-arm64
8+
9+
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment below.)
10+
11+
// Welcome, Build Wrangler!
12+
//
13+
// This file lists APIs that have recently changed in a way that potentially
14+
// indicates an ABI- or source-breaking problem.
15+
//
16+
// A failure in this test indicates that there is a potential breaking change in
17+
// the Standard Library. If you observe a failure outside of a PR test, please
18+
// reach out to the Standard Library team directly to make sure this gets
19+
// resolved quickly! If your own PR fails in this test, you probably have an
20+
// ABI- or source-breaking change in your commits. Please go and fix it.
21+
//
22+
// Please DO NOT DISABLE THIS TEST. In addition to ignoring the current set of
23+
// ABI breaks, XFAILing this test also silences any future ABI breaks that may
24+
// land on this branch, which simply generates extra work for the next person
25+
// that picks up the mess.
26+
//
27+
// Instead of disabling this test, you'll need to extend the list of expected
28+
// changes at the bottom. (You'll also need to do this if your own PR triggers
29+
// false positives, or if you have special permission to break things.) You can
30+
// find a diff of what needs to be added in the output of the failed test run.
31+
// The order of lines doesn't matter, and you can also include comments to refer
32+
// to any bugs you filed.
33+
//
34+
// Thank you for your help ensuring the stdlib remains compatible with its past!
35+
// -- Your friendly stdlib engineers
36+
37+
// Standard Library Symbols
38+
39+
// Swift._getRetainCount(Swift.AnyObject) -> Swift.UInt
40+
Added: _$ss15_getRetainCountySuyXlF
41+
42+
// Swift._getWeakRetainCount(Swift.AnyObject) -> Swift.UInt
43+
Added: _$ss19_getWeakRetainCountySuyXlF
44+
45+
// Swift._getUnownedRetainCount(Swift.AnyObject) -> Swift.UInt
46+
Added: _$ss22_getUnownedRetainCountySuyXlF
47+
48+
// Runtime Symbols
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %llvm-nm -g --defined-only -f just-symbols %stdlib_dir/x86_64/libswiftCore.dylib > %t/symbols
3+
// RUN: %abi-symbol-checker %s %t/symbols --base %S/stdlib.swift
4+
// RUN: diff -u %S/../../Inputs/macOS/x86_64/stdlib/baseline-asserts %t/symbols
5+
6+
// REQUIRES: swift_stdlib_asserts
7+
// REQUIRES: STDLIB_VARIANT=macosx-x86_64
8+
9+
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment below.)
10+
11+
// Welcome, Build Wrangler!
12+
//
13+
// This file lists APIs that have recently changed in a way that potentially
14+
// indicates an ABI- or source-breaking problem.
15+
//
16+
// A failure in this test indicates that there is a potential breaking change in
17+
// the Standard Library. If you observe a failure outside of a PR test, please
18+
// reach out to the Standard Library team directly to make sure this gets
19+
// resolved quickly! If your own PR fails in this test, you probably have an
20+
// ABI- or source-breaking change in your commits. Please go and fix it.
21+
//
22+
// Please DO NOT DISABLE THIS TEST. In addition to ignoring the current set of
23+
// ABI breaks, XFAILing this test also silences any future ABI breaks that may
24+
// land on this branch, which simply generates extra work for the next person
25+
// that picks up the mess.
26+
//
27+
// Instead of disabling this test, you'll need to extend the list of expected
28+
// changes at the bottom. (You'll also need to do this if your own PR triggers
29+
// false positives, or if you have special permission to break things.) You can
30+
// find a diff of what needs to be added in the output of the failed test run.
31+
// The order of lines doesn't matter, and you can also include comments to refer
32+
// to any bugs you filed.
33+
//
34+
// Thank you for your help ensuring the stdlib remains compatible with its past!
35+
// -- Your friendly stdlib engineers
36+
37+
// *** NOTE: ***
38+
// You will normally add new entries in 'abi/macOS/x86_64/stdlib.swift' instead
39+
// of this file. This file is dedicated for assert only symbols.
40+
41+
// Standard Library Symbols
42+
43+
// Runtime Symbols

test/abi/macOS/x86_64/stdlib.swift

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %llvm-nm -g --defined-only -f just-symbols %stdlib_dir/x86_64/libswiftCore.dylib > %t/symbols
3+
// RUN: %abi-symbol-checker %s %t/symbols
4+
// RUN: diff -u %S/../../Inputs/macOS/x86_64/stdlib/baseline %t/symbols
5+
6+
// REQUIRES: swift_stdlib_no_asserts
7+
// REQUIRES: STDLIB_VARIANT=macosx-x86_64
8+
9+
// *** DO NOT DISABLE OR XFAIL THIS TEST. *** (See comment below.)
10+
11+
// Welcome, Build Wrangler!
12+
//
13+
// This file lists APIs that have recently changed in a way that potentially
14+
// indicates an ABI- or source-breaking problem.
15+
//
16+
// A failure in this test indicates that there is a potential breaking change in
17+
// the Standard Library. If you observe a failure outside of a PR test, please
18+
// reach out to the Standard Library team directly to make sure this gets
19+
// resolved quickly! If your own PR fails in this test, you probably have an
20+
// ABI- or source-breaking change in your commits. Please go and fix it.
21+
//
22+
// Please DO NOT DISABLE THIS TEST. In addition to ignoring the current set of
23+
// ABI breaks, XFAILing this test also silences any future ABI breaks that may
24+
// land on this branch, which simply generates extra work for the next person
25+
// that picks up the mess.
26+
//
27+
// Instead of disabling this test, you'll need to extend the list of expected
28+
// changes at the bottom. (You'll also need to do this if your own PR triggers
29+
// false positives, or if you have special permission to break things.) You can
30+
// find a diff of what needs to be added in the output of the failed test run.
31+
// The order of lines doesn't matter, and you can also include comments to refer
32+
// to any bugs you filed.
33+
//
34+
// Thank you for your help ensuring the stdlib remains compatible with its past!
35+
// -- Your friendly stdlib engineers
36+
37+
// Standard Library Symbols
38+
39+
// Swift._getRetainCount(Swift.AnyObject) -> Swift.UInt
40+
Added: _$ss15_getRetainCountySuyXlF
41+
42+
// Swift._getWeakRetainCount(Swift.AnyObject) -> Swift.UInt
43+
Added: _$ss19_getWeakRetainCountySuyXlF
44+
45+
// Swift._getUnownedRetainCount(Swift.AnyObject) -> Swift.UInt
46+
Added: _$ss22_getUnownedRetainCountySuyXlF
47+
48+
// Runtime Symbols

test/lit.cfg

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ config.swift_libexec_dir = make_path(config.swift, '..', '..', 'libexec')
360360
config.swift_share_dir = make_path(config.swift, '..', '..', 'share')
361361
config.round_trip_syntax_test = make_path(config.swift_utils, 'round-trip-syntax-test')
362362
config.refactor_check_compiles = make_path(config.swift_utils, 'refactor-check-compiles.py')
363+
config.abi_symbol_checker = make_path(config.swift_utils, 'swift-abi-symbol-checker.py')
363364

364365
config.link = lit.util.which('link', config.environment.get('PATH', '')) or \
365366
lit.util.which('lld-link', config.environment.get('PATH', ''))
@@ -778,6 +779,8 @@ config.available_features.add("VENDOR=" + run_vendor)
778779

779780
config.available_features.add("SWIFT_VERSION=" + swift_version)
780781

782+
config.available_features.add("STDLIB_VARIANT={}".format(config.variant_suffix[1:]))
783+
781784
if "optimized_stdlib" in config.available_features:
782785
config.available_features.add("optimized_stdlib_" + run_cpu)
783786

@@ -2596,6 +2599,7 @@ config.substitutions.append(('%scale-test',
25962599
'{} {} --swiftc-binary={} --tmpdir=%t --exclude-timers'.format(
25972600
shell_quote(sys.executable), config.scale_test,
25982601
config.swiftc)))
2602+
config.substitutions.append(('%abi-symbol-checker', '%s %s' % (shell_quote(sys.executable), config.abi_symbol_checker)))
25992603
config.substitutions.append(('%target-sil-opt\(mock-sdk:([^)]+)\)',
26002604
SubstituteCaptures(r'%s \1 %s' % (
26012605
escape_for_substitute_captures(subst_target_sil_opt_mock_sdk),

utils/swift-abi-symbol-checker.py

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

0 commit comments

Comments
 (0)