Skip to content

swift-api-digester: teach the tool to compare two SDKs directly #25506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#if !defined(__FOOSUB_H__)
#define __FOOSUB_H__ 1

int fooSubFunc1(int a);

enum FooSubEnum1 {
FooSubEnum1X,
FooSubEnum1Y
};

enum {
FooSubUnnamedEnumeratorA1
};

#endif /* ! __FOOSUB_H__ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* Foo.h
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
*/
#if !defined(__FOO_H__)
#define __FOO_H__ 1

#import <FooSub/FooSub.h>

void removedFunction(void);

#endif /* ! __FOO_H__ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
framework module Foo {
umbrella header "Foo.h"
export *
framework module FooSub {
umbrella header "FooSub.h"
export *
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// swift-interface-format-version: 1.0
// swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14)
// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo
import Swift
public class RemovedClass {
@objc deinit
}
2 changes: 2 additions & 0 deletions test/api-digester/Inputs/mock-sdk-modules.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Foo
SwiftFoo
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#if !defined(__FOOSUB_H__)
#define __FOOSUB_H__ 1

int fooSubFunc1(int a);

enum FooSubEnum1 {
FooSubEnum1X,
FooSubEnum1Y
};

enum {
FooSubUnnamedEnumeratorA1
};

#endif /* ! __FOOSUB_H__ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* Foo.h
Copyright (c) 1815, Napoleon Bonaparte. All rights reserved.
*/
#if !defined(__FOO_H__)
#define __FOO_H__ 1

#import <FooSub/FooSub.h>

#endif /* ! __FOO_H__ */
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
framework module Foo {
umbrella header "Foo.h"
export *
framework module FooSub {
umbrella header "FooSub.h"
export *
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// swift-interface-format-version: 1.0
// swift-tools-version: Apple Swift version 5.1 (swiftlang-1100.0.38 clang-1100.0.20.14)
// swift-module-flags: -target x86_64-apple-macos10.14 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name SwiftFoo
import Swift
public class AddedClass {
@objc deinit
}
2 changes: 2 additions & 0 deletions test/api-digester/Outputs/mock-sdk-api.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Foo(Foo.h): Func removedFunction() has been removed
SwiftFoo: Class RemovedClass has been removed
4 changes: 2 additions & 2 deletions test/api-digester/compare-dump-abi-parsable-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

// 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
// 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
// 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
// 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

// RUN: %clang -E -P -x c %S/Outputs/Cake-abi.txt -o - | sed '/^\s*$/d' > %t.expected
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
// RUN: diff -u %t.expected %t.result.tmp
// RUN: diff -u %t.expected %t.result.tmp
4 changes: 2 additions & 2 deletions test/api-digester/compare-dump-parsable-interface.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

// 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
// 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
// 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
// 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

// RUN: %clang -E -P -x c %S/Outputs/Cake.txt -o - | sed '/^\s*$/d' > %t.expected
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
// RUN: diff -u %t.expected %t.result.tmp
// RUN: diff -u %t.expected %t.result.tmp
12 changes: 12 additions & 0 deletions test/api-digester/compare-two-sdks.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// REQUIRES: OS=macosx

// RUN: %empty-directory(%t.mod1)
// RUN: %empty-directory(%t.mod2)
// RUN: %empty-directory(%t.sdk)
// RUN: %empty-directory(%t.module-cache)

// 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 -abort-on-module-fail -target x86_64-apple-macos10.14

// RUN: %clang -E -P -x c %S/Outputs/mock-sdk-api.txt -o - | sed '/^\s*$/d' > %t.expected
// RUN: %clang -E -P -x c %t.result -o - | sed '/^\s*$/d' > %t.result.tmp
// RUN: diff -u %t.expected %t.result.tmp
66 changes: 49 additions & 17 deletions tools/swift-api-digester/swift-api-digester.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ static llvm::cl::opt<std::string>
SDK("sdk", llvm::cl::desc("path to the SDK to build against"),
llvm::cl::cat(Category));

static llvm::cl::opt<std::string>
BaselineSDK("bsdk", llvm::cl::desc("path to the baseline SDK to import frameworks"),
llvm::cl::cat(Category));

static llvm::cl::opt<std::string>
Triple("target", llvm::cl::desc("target triple"),
llvm::cl::cat(Category));
Expand All @@ -98,6 +102,10 @@ static llvm::cl::list<std::string>
FrameworkPaths("F", llvm::cl::desc("add a directory to the framework search path"),
llvm::cl::cat(Category));

static llvm::cl::list<std::string>
BaselineFrameworkPaths("BF", llvm::cl::desc("add a directory to the baseline framework search path"),
llvm::cl::cat(Category));

static llvm::cl::list<std::string>
BaselineModuleInputPaths("BI", llvm::cl::desc("add a module for baseline input"),
llvm::cl::cat(Category));
Expand Down Expand Up @@ -2084,6 +2092,10 @@ static int diagnoseModuleChange(SDKContext &Ctx, SDKNodeRoot *LeftModule,
assert(LeftModule);
assert(RightModule);
llvm::raw_ostream *OS = &llvm::errs();
if (!LeftModule || !RightModule) {
*OS << "Cannot diagnose null SDKNodeRoot";
exit(1);
}
std::unique_ptr<llvm::raw_ostream> FileOS;
if (!OutputPath.empty()) {
std::error_code EC;
Expand Down Expand Up @@ -2270,22 +2282,34 @@ static int readFileLineByLine(StringRef Path, llvm::StringSet<> &Lines) {
// without being given the address of a function in the main executable).
void anchorForGetMainExecutable() {}

static void setSDKPath(CompilerInvocation &InitInvok, bool IsBaseline) {
if (IsBaseline) {
// Set baseline SDK
if (!options::BaselineSDK.empty()) {
InitInvok.setSDKPath(options::BaselineSDK);
}
} else {
// Set current SDK
if (!options::SDK.empty()) {
InitInvok.setSDKPath(options::SDK);
} else if (const char *SDKROOT = getenv("SDKROOT")) {
InitInvok.setSDKPath(SDKROOT);
} else {
llvm::errs() << "Provide '-sdk <path>' option or run with 'xcrun -sdk <..>\
swift-api-digester'\n";
exit(1);
}
}
}

static int prepareForDump(const char *Main,
CompilerInvocation &InitInvok,
llvm::StringSet<> &Modules,
bool IsBaseline = false) {
InitInvok.setMainExecutablePath(fs::getMainExecutable(Main,
reinterpret_cast<void *>(&anchorForGetMainExecutable)));
InitInvok.setModuleName("swift_ide_test");
if (!options::SDK.empty()) {
InitInvok.setSDKPath(options::SDK);
} else if (const char *SDKROOT = getenv("SDKROOT")) {
InitInvok.setSDKPath(SDKROOT);
} else {
llvm::errs() << "Provide '-sdk <path>' option or run with 'xcrun -sdk <..>\
swift-api-digester'\n";
return 1;
}
setSDKPath(InitInvok, IsBaseline);

if (!options::Triple.empty())
InitInvok.setTargetTriple(options::Triple);
Expand All @@ -2308,36 +2332,39 @@ static int prepareForDump(const char *Main,
}
if (!isValid) {
llvm::errs() << "Unsupported Swift Version.\n";
return 1;
exit(1);
}
}

if (!options::ResourceDir.empty()) {
InitInvok.setRuntimeResourcePath(options::ResourceDir);
}
std::vector<SearchPathOptions::FrameworkSearchPath> FramePaths;
for (const auto &path : options::FrameworkPaths) {
FramePaths.push_back({path, /*isSystem=*/false});
}
for (const auto &path : options::CCSystemFrameworkPaths) {
FramePaths.push_back({path, /*isSystem=*/true});
}
InitInvok.setFrameworkSearchPaths(FramePaths);
if (IsBaseline) {
for (const auto &path : options::BaselineFrameworkPaths) {
FramePaths.push_back({path, /*isSystem=*/false});
}
InitInvok.setImportSearchPaths(options::BaselineModuleInputPaths);
} else {
for (const auto &path : options::FrameworkPaths) {
FramePaths.push_back({path, /*isSystem=*/false});
}
InitInvok.setImportSearchPaths(options::ModuleInputPaths);
}
InitInvok.setFrameworkSearchPaths(FramePaths);
if (!options::ModuleList.empty()) {
if (readFileLineByLine(options::ModuleList, Modules))
return 1;
exit(1);
}
for (auto M : options::ModuleNames) {
Modules.insert(M);
}
if (Modules.empty()) {
llvm::errs() << "Need to specify -include-all or -module <name>\n";
return 1;
exit(1);
}
return 0;
}
Expand Down Expand Up @@ -2406,6 +2433,11 @@ static SDKNodeRoot *getSDKRoot(const char *Main, SDKContext &Ctx,
return getSDKNodeRoot(Ctx, Invok, Modules, Opts);
}

static bool hasBaselineInput() {
return !options::BaselineModuleInputPaths.empty() ||
!options::BaselineFrameworkPaths.empty() || !options::BaselineSDK.empty();
}

int main(int argc, char *argv[]) {
PROGRAM_START(argc, argv);
INITIALIZE_LLVM();
Expand All @@ -2428,7 +2460,7 @@ int main(int argc, char *argv[]) {
case ActionType::MigratorGen:
case ActionType::DiagnoseSDKs: {
bool CompareJson = options::SDKJsonPaths.size() == 2;
if (!CompareJson && options::BaselineModuleInputPaths.empty()) {
if (!CompareJson && !hasBaselineInput()) {
llvm::errs() << "Only two SDK versions can be compared\n";
llvm::cl::PrintHelpMessage();
return 1;
Expand Down