Skip to content

Commit cca6cb5

Browse files
committed
swift-api-digester: teach the tool to compare two SDKs directly
With module stability from the compiler, we can now use an earlier version of the SDK as the baseline and compare the new SDK with it. This patch adds a new -bsdk flag to the tool to specify the baseline SDK path.
1 parent 81f4b90 commit cca6cb5

File tree

12 files changed

+133
-21
lines changed

12 files changed

+133
-21
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#if !defined(__FOOSUB_H__)
2+
#define __FOOSUB_H__ 1
3+
4+
int fooSubFunc1(int a);
5+
6+
enum FooSubEnum1 {
7+
FooSubEnum1X,
8+
FooSubEnum1Y
9+
};
10+
11+
enum {
12+
FooSubUnnamedEnumeratorA1
13+
};
14+
15+
#endif /* ! __FOOSUB_H__ */
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/* Foo.h
2+
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
3+
*/
4+
#if !defined(__FOO_H__)
5+
#define __FOO_H__ 1
6+
7+
#import <FooSub/FooSub.h>
8+
9+
void removedFunction(void);
10+
11+
#endif /* ! __FOO_H__ */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
framework module Foo {
2+
umbrella header "Foo.h"
3+
export *
4+
framework module FooSub {
5+
umbrella header "FooSub.h"
6+
export *
7+
}
8+
}
9+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Foo
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#if !defined(__FOOSUB_H__)
2+
#define __FOOSUB_H__ 1
3+
4+
int fooSubFunc1(int a);
5+
6+
enum FooSubEnum1 {
7+
FooSubEnum1X,
8+
FooSubEnum1Y
9+
};
10+
11+
enum {
12+
FooSubUnnamedEnumeratorA1
13+
};
14+
15+
#endif /* ! __FOOSUB_H__ */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/* Foo.h
2+
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
3+
*/
4+
#if !defined(__FOO_H__)
5+
#define __FOO_H__ 1
6+
7+
#import <FooSub/FooSub.h>
8+
9+
#endif /* ! __FOO_H__ */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
framework module Foo {
2+
umbrella header "Foo.h"
3+
export *
4+
framework module FooSub {
5+
umbrella header "FooSub.h"
6+
export *
7+
}
8+
}
9+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Foo(Foo.h): Func removedFunction() has been removed

test/api-digester/compare-dump-abi-parsable-interface.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.mod1/cake.swiftinterface %S/Inputs/cake_baseline/cake.swift -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache
77
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.mod2/cake.swiftinterface %S/Inputs/cake_current/cake.swift -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache
8-
// RUN: %api-digester -diagnose-sdk -print-module -module cake -BI %t.mod1 -BI %S/Inputs/APINotesLeft -I %t.mod2 -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -module-cache-path %t.module-cache -o %t.result -abi
8+
// RUN: %api-digester -diagnose-sdk -print-module -module cake -BI %t.mod1 -BI %S/Inputs/APINotesLeft -I %t.mod2 -I %S/Inputs/APINotesRight -sdk %clang-importer-sdk-path -bsdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.result -abi
99

1010
// RUN: %clang -E -P -x c %S/Outputs/Cake-abi.txt -o - | sed '/^\s*$/d' > %t.expected
1111
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
12-
// RUN: diff -u %t.expected %t.result.tmp
12+
// RUN: diff -u %t.expected %t.result.tmp

test/api-digester/compare-dump-parsable-interface.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55

66
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.mod1/cake.swiftinterface %S/Inputs/cake_baseline/cake.swift -I %S/Inputs/APINotesLeft %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache
77
// RUN: %target-swift-frontend -typecheck -emit-parseable-module-interface-path %t.mod2/cake.swiftinterface %S/Inputs/cake_current/cake.swift -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -parse-as-library -enable-library-evolution -disable-objc-attr-requires-foundation-module -module-cache-path %t.module-cache
8-
// RUN: %api-digester -diagnose-sdk -print-module -module cake -BI %t.mod1 -BI %S/Inputs/APINotesLeft -I %t.mod2 -I %S/Inputs/APINotesRight %clang-importer-sdk-nosource -module-cache-path %t.module-cache -o %t.result
8+
// RUN: %api-digester -diagnose-sdk -print-module -module cake -BI %t.mod1 -BI %S/Inputs/APINotesLeft -I %t.mod2 -I %S/Inputs/APINotesRight -sdk %clang-importer-sdk-path -bsdk %clang-importer-sdk-path -module-cache-path %t.module-cache -o %t.result
99

1010
// RUN: %clang -E -P -x c %S/Outputs/Cake.txt -o - | sed '/^\s*$/d' > %t.expected
1111
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
12-
// RUN: diff -u %t.expected %t.result.tmp
12+
// RUN: diff -u %t.expected %t.result.tmp
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// RUN: %empty-directory(%t.mod1)
2+
// RUN: %empty-directory(%t.mod2)
3+
// RUN: %empty-directory(%t.sdk)
4+
// RUN: %empty-directory(%t.module-cache)
5+
6+
// RUN: %api-digester -diagnose-sdk -print-module -module-list-file %S/Inputs/mock-sdk-modules.txt -sdk %S/Inputs/mock-sdk.sdk -bsdk %S/Inputs/mock-sdk-baseline.sdk -module-cache-path %t.module-cache -o %t.result
7+
8+
// RUN: %clang -E -P -x c %S/Outputs/mock-sdk-api.txt -o - | sed '/^\s*$/d' > %t.expected
9+
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
10+
// RUN: diff -u %t.expected %t.result.tmp

tools/swift-api-digester/swift-api-digester.cpp

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ static llvm::cl::opt<std::string>
8181
SDK("sdk", llvm::cl::desc("path to the SDK to build against"),
8282
llvm::cl::cat(Category));
8383

84+
static llvm::cl::opt<std::string>
85+
BaselineSDK("bsdk", llvm::cl::desc("path to the baseline SDK to import frameworks"),
86+
llvm::cl::cat(Category));
87+
8488
static llvm::cl::opt<std::string>
8589
Triple("target", llvm::cl::desc("target triple"),
8690
llvm::cl::cat(Category));
@@ -98,6 +102,10 @@ static llvm::cl::list<std::string>
98102
FrameworkPaths("F", llvm::cl::desc("add a directory to the framework search path"),
99103
llvm::cl::cat(Category));
100104

105+
static llvm::cl::list<std::string>
106+
BaselineFrameworkPaths("BF", llvm::cl::desc("add a directory to the baseline framework search path"),
107+
llvm::cl::cat(Category));
108+
101109
static llvm::cl::list<std::string>
102110
BaselineModuleInputPaths("BI", llvm::cl::desc("add a module for baseline input"),
103111
llvm::cl::cat(Category));
@@ -2084,6 +2092,10 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule,
20842092
assert(LeftModule);
20852093
assert(RightModule);
20862094
llvm::raw_ostream *OS = &llvm::errs();
2095+
if (!LeftModule || !RightModule) {
2096+
*OS << "Cannot diagnose null SDKNodeRoot";
2097+
exit(1);
2098+
}
20872099
std::unique_ptr<llvm::raw_ostream> FileOS;
20882100
if (!OutputPath.empty()) {
20892101
std::error_code EC;
@@ -2270,22 +2282,34 @@ static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) {
22702282
// without being given the address of a function in the main executable).
22712283
void anchorForGetMainExecutable() {}
22722284

2285+
static void setSDKPath(CompilerInvocation &InitInvok, bool IsBaseline) {
2286+
if (IsBaseline) {
2287+
// Set baseline SDK
2288+
if (!options::BaselineSDK.empty()) {
2289+
InitInvok.setSDKPath(options::BaselineSDK);
2290+
}
2291+
} else {
2292+
// Set current SDK
2293+
if (!options::SDK.empty()) {
2294+
InitInvok.setSDKPath(options::SDK);
2295+
} else if (const char *SDKROOT = getenv("SDKROOT")) {
2296+
InitInvok.setSDKPath(SDKROOT);
2297+
} else {
2298+
llvm::errs() << "Provide '-sdk <path>' option or run with 'xcrun -sdk <..>\
2299+
swift-api-digester'\n";
2300+
exit(1);
2301+
}
2302+
}
2303+
}
2304+
22732305
static int prepareForDump(const char *Main,
22742306
CompilerInvocation &InitInvok,
22752307
llvm::StringSet<> &Modules,
22762308
bool IsBaseline = false) {
22772309
InitInvok.setMainExecutablePath(fs::getMainExecutable(Main,
22782310
reinterpret_cast<void *>(&anchorForGetMainExecutable)));
22792311
InitInvok.setModuleName("swift_ide_test");
2280-
if (!options::SDK.empty()) {
2281-
InitInvok.setSDKPath(options::SDK);
2282-
} else if (const char *SDKROOT = getenv("SDKROOT")) {
2283-
InitInvok.setSDKPath(SDKROOT);
2284-
} else {
2285-
llvm::errs() << "Provide '-sdk <path>' option or run with 'xcrun -sdk <..>\
2286-
swift-api-digester'\n";
2287-
return 1;
2288-
}
2312+
setSDKPath(InitInvok, IsBaseline);
22892313

22902314
if (!options::Triple.empty())
22912315
InitInvok.setTargetTriple(options::Triple);
@@ -2308,36 +2332,39 @@ static int prepareForDump(const char *Main,
23082332
}
23092333
if (!isValid) {
23102334
llvm::errs() << "Unsupported Swift Version.\n";
2311-
return 1;
2335+
exit(1);
23122336
}
23132337
}
23142338

23152339
if (!options::ResourceDir.empty()) {
23162340
InitInvok.setRuntimeResourcePath(options::ResourceDir);
23172341
}
23182342
std::vector<SearchPathOptions::FrameworkSearchPath> FramePaths;
2319-
for (const auto &path : options::FrameworkPaths) {
2320-
FramePaths.push_back({path, /*isSystem=*/false});
2321-
}
23222343
for (const auto &path : options::CCSystemFrameworkPaths) {
23232344
FramePaths.push_back({path, /*isSystem=*/true});
23242345
}
2325-
InitInvok.setFrameworkSearchPaths(FramePaths);
23262346
if (IsBaseline) {
2347+
for (const auto &path : options::BaselineFrameworkPaths) {
2348+
FramePaths.push_back({path, /*isSystem=*/false});
2349+
}
23272350
InitInvok.setImportSearchPaths(options::BaselineModuleInputPaths);
23282351
} else {
2352+
for (const auto &path : options::FrameworkPaths) {
2353+
FramePaths.push_back({path, /*isSystem=*/false});
2354+
}
23292355
InitInvok.setImportSearchPaths(options::ModuleInputPaths);
23302356
}
2357+
InitInvok.setFrameworkSearchPaths(FramePaths);
23312358
if (!options::ModuleList.empty()) {
23322359
if (readFileLineByLine(options::ModuleList, Modules))
2333-
return 1;
2360+
exit(1);
23342361
}
23352362
for (auto M : options::ModuleNames) {
23362363
Modules.insert(M);
23372364
}
23382365
if (Modules.empty()) {
23392366
llvm::errs() << "Need to specify -include-all or -module <name>\n";
2340-
return 1;
2367+
exit(1);
23412368
}
23422369
return 0;
23432370
}
@@ -2406,6 +2433,11 @@ static SDKNodeRoot *getSDKRoot(const char *Main, SDKContext &Ctx,
24062433
return getSDKNodeRoot(Ctx, Invok, Modules, Opts);
24072434
}
24082435

2436+
static bool hasBaselineInput() {
2437+
return !options::BaselineModuleInputPaths.empty() ||
2438+
!options::BaselineFrameworkPaths.empty() || !options::BaselineSDK.empty();
2439+
}
2440+
24092441
int main(int argc, char *argv[]) {
24102442
PROGRAM_START(argc, argv);
24112443
INITIALIZE_LLVM();
@@ -2428,7 +2460,7 @@ int main(int argc, char *argv[]) {
24282460
case ActionType::MigratorGen:
24292461
case ActionType::DiagnoseSDKs: {
24302462
bool CompareJson = options::SDKJsonPaths.size() == 2;
2431-
if (!CompareJson && options::BaselineModuleInputPaths.empty()) {
2463+
if (!CompareJson && !hasBaselineInput()) {
24322464
llvm::errs() << "Only two SDK versions can be compared\n";
24332465
llvm::cl::PrintHelpMessage();
24342466
return 1;

0 commit comments

Comments
 (0)