Skip to content

Commit 5415541

Browse files
committed
Frontend: teach -compile-module-from-interface action to emit ABI descriptor as byproduct
We have implemented a libSwiftDriver-based tool to generate prebuilt module cache for entire SDKs. Anchored on the same infrastructure, we could also generate ABI baselines for entire SDKs.
1 parent 3bb780e commit 5415541

15 files changed

+100
-8
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ ERROR(error_mode_cannot_emit_module_summary,none,
129129
"this mode does not support emitting module summary files", ())
130130
ERROR(error_mode_cannot_emit_symbol_graph,none,
131131
"this mode does not support emitting symbol graph files", ())
132+
ERROR(error_mode_cannot_emit_abi_descriptor,none,
133+
"this mode does not support emitting ABI descriptor", ())
132134
ERROR(cannot_emit_ir_skipping_function_bodies,none,
133135
"the -experimental-skip-*-function-bodies* flags do not support "
134136
"emitting IR", ())

include/swift/Basic/SupplementaryOutputPaths.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@ struct SupplementaryOutputPaths {
153153
/// The path to which we should emit module summary file.
154154
std::string ModuleSummaryOutputPath;
155155

156+
/// The output path to generate ABI baseline.
157+
std::string ABIDescriptorOutputPath;
158+
156159
SupplementaryOutputPaths() = default;
157160
SupplementaryOutputPaths(const SupplementaryOutputPaths &) = default;
158161

@@ -186,6 +189,8 @@ struct SupplementaryOutputPaths {
186189
fn(LdAddCFilePath);
187190
if (!ModuleSummaryOutputPath.empty())
188191
fn(ModuleSummaryOutputPath);
192+
if (!ABIDescriptorOutputPath.empty())
193+
fn(ABIDescriptorOutputPath);
189194
}
190195

191196
bool empty() const {
@@ -194,7 +199,7 @@ struct SupplementaryOutputPaths {
194199
ReferenceDependenciesFilePath.empty() &&
195200
SerializedDiagnosticsPath.empty() && LoadedModuleTracePath.empty() &&
196201
TBDPath.empty() && ModuleInterfaceOutputPath.empty() &&
197-
ModuleSourceInfoOutputPath.empty() && LdAddCFilePath.empty();
202+
ModuleSourceInfoOutputPath.empty() && LdAddCFilePath.empty() && ABIDescriptorOutputPath.empty();
198203
}
199204
};
200205
} // namespace swift

include/swift/Frontend/FrontendInputsAndOutputs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ class FrontendInputsAndOutputs {
256256
bool hasModuleSourceInfoOutputPath() const;
257257
bool hasModuleInterfaceOutputPath() const;
258258
bool hasPrivateModuleInterfaceOutputPath() const;
259+
bool hasABIDescriptorOutputPath() const;
259260
bool hasModuleSummaryOutputPath() const;
260261
bool hasTBDPath() const;
261262

include/swift/Frontend/FrontendOptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ class FrontendOptions {
423423
static bool canActionEmitModuleDoc(ActionType);
424424
static bool canActionEmitModuleSummary(ActionType);
425425
static bool canActionEmitInterface(ActionType);
426+
static bool canActionEmitABIDescriptor(ActionType);
426427

427428
public:
428429
static bool doesActionGenerateSIL(ActionType);

include/swift/Frontend/ModuleInterfaceLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ class ModuleInterfaceLoader : public SerializedModuleLoaderBase {
414414
const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts,
415415
const ClangImporterOptions &ClangOpts, StringRef CacheDir,
416416
StringRef PrebuiltCacheDir, StringRef ModuleName, StringRef InPath,
417-
StringRef OutPath, bool SerializeDependencyHashes,
417+
StringRef OutPath, StringRef ABIOutputPath, bool SerializeDependencyHashes,
418418
bool TrackSystemDependencies, ModuleInterfaceLoaderOptions Opts,
419419
RequireOSSAModules_t RequireOSSAModules);
420420
};

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ def emit_fixits_path
6464
: Separate<["-"], "emit-fixits-path">, MetaVarName<"<path>">,
6565
HelpText<"Output compiler fixits as source edits to <path>">;
6666

67+
def emit_abi_descriptor_path
68+
: Separate<["-"], "emit-abi-descriptor-path">, MetaVarName<"<path>">,
69+
HelpText<"Output the ABI descriptor of current module to <path>">;
70+
6771
def serialize_module_interface_dependency_hashes
6872
: Flag<["-"], "serialize-module-interface-dependency-hashes">,
6973
Flags<[HelpHidden]>;

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -594,6 +594,11 @@ bool ArgsToFrontendOptionsConverter::checkUnusedSupplementaryOutputPaths()
594594
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_module_doc);
595595
return true;
596596
}
597+
if (!FrontendOptions::canActionEmitABIDescriptor(Opts.RequestedAction) &&
598+
Opts.InputsAndOutputs.hasABIDescriptorOutputPath()) {
599+
Diags.diagnose(SourceLoc(), diag::error_mode_cannot_emit_abi_descriptor);
600+
return true;
601+
}
597602
// If we cannot emit module doc, we cannot emit source information file either.
598603
if (!FrontendOptions::canActionEmitModuleDoc(Opts.RequestedAction) &&
599604
Opts.InputsAndOutputs.hasModuleSourceInfoOutputPath()) {

lib/Frontend/ArgsToFrontendOutputsConverter.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,14 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
341341
options::OPT_emit_ldadd_cfile_path);
342342
auto moduleSummaryOutput = getSupplementaryFilenamesFromArguments(
343343
options::OPT_emit_module_summary_path);
344+
auto abiDescriptorOutput = getSupplementaryFilenamesFromArguments(
345+
options::OPT_emit_abi_descriptor_path);
344346
if (!objCHeaderOutput || !moduleOutput || !moduleDocOutput ||
345347
!dependenciesFile || !referenceDependenciesFile ||
346348
!serializedDiagnostics || !fixItsOutput || !loadedModuleTrace || !TBD ||
347349
!moduleInterfaceOutput || !privateModuleInterfaceOutput ||
348-
!moduleSourceInfoOutput || !ldAddCFileOutput || !moduleSummaryOutput) {
350+
!moduleSourceInfoOutput || !ldAddCFileOutput || !moduleSummaryOutput ||
351+
!abiDescriptorOutput) {
349352
return None;
350353
}
351354
std::vector<SupplementaryOutputPaths> result;
@@ -368,6 +371,7 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
368371
sop.ModuleSourceInfoOutputPath = (*moduleSourceInfoOutput)[i];
369372
sop.LdAddCFilePath = (*ldAddCFileOutput)[i];
370373
sop.ModuleSummaryOutputPath = (*moduleSummaryOutput)[i];
374+
sop.ABIDescriptorOutputPath = (*abiDescriptorOutput)[i];
371375
result.push_back(sop);
372376
}
373377
return result;
@@ -466,6 +470,8 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
466470
auto PrivateModuleInterfaceOutputPath =
467471
pathsFromArguments.PrivateModuleInterfaceOutputPath;
468472

473+
// There is no non-path form of -emit-abi-descriptor-path
474+
auto ABIDescriptorOutputPath = pathsFromArguments.ABIDescriptorOutputPath;
469475
ID emitModuleOption;
470476
std::string moduleExtension;
471477
std::string mainOutputIfUsableForModule;
@@ -492,6 +498,7 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
492498
sop.ModuleSourceInfoOutputPath = moduleSourceInfoOutputPath;
493499
sop.LdAddCFilePath = pathsFromArguments.LdAddCFilePath;
494500
sop.ModuleSummaryOutputPath = moduleSummaryOutputPath;
501+
sop.ABIDescriptorOutputPath = ABIDescriptorOutputPath;
495502
return sop;
496503
}
497504

lib/Frontend/FrontendInputsAndOutputs.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,12 @@ bool FrontendInputsAndOutputs::hasPrivateModuleInterfaceOutputPath() const {
503503
return outs.PrivateModuleInterfaceOutputPath;
504504
});
505505
}
506+
bool FrontendInputsAndOutputs::hasABIDescriptorOutputPath() const {
507+
return hasSupplementaryOutputPath(
508+
[](const SupplementaryOutputPaths &outs) -> const std::string & {
509+
return outs.ABIDescriptorOutputPath;
510+
});
511+
}
506512
bool FrontendInputsAndOutputs::hasModuleSummaryOutputPath() const {
507513
return hasSupplementaryOutputPath(
508514
[](const SupplementaryOutputPaths &outs) -> const std::string & {

lib/Frontend/FrontendOptions.cpp

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,47 @@ bool FrontendOptions::canActionEmitLoadedModuleTrace(ActionType action) {
524524
}
525525
llvm_unreachable("unhandled action");
526526
}
527-
527+
bool FrontendOptions::canActionEmitABIDescriptor(ActionType action) {
528+
switch (action) {
529+
case ActionType::CompileModuleFromInterface:
530+
return true;
531+
case ActionType::NoneAction:
532+
case ActionType::Parse:
533+
case ActionType::ResolveImports:
534+
case ActionType::Typecheck:
535+
case ActionType::DumpParse:
536+
case ActionType::DumpInterfaceHash:
537+
case ActionType::DumpAST:
538+
case ActionType::EmitSyntax:
539+
case ActionType::PrintAST:
540+
case ActionType::EmitPCH:
541+
case ActionType::DumpScopeMaps:
542+
case ActionType::DumpTypeRefinementContexts:
543+
case ActionType::DumpTypeInfo:
544+
case ActionType::EmitSILGen:
545+
case ActionType::TypecheckModuleFromInterface:
546+
case ActionType::Immediate:
547+
case ActionType::REPL:
548+
case ActionType::EmitPCM:
549+
case ActionType::DumpPCM:
550+
case ActionType::ScanDependencies:
551+
case ActionType::PrintVersion:
552+
case ActionType::PrintFeature:
553+
case ActionType::MergeModules:
554+
case ActionType::EmitModuleOnly:
555+
case ActionType::EmitSIL:
556+
case ActionType::EmitSIBGen:
557+
case ActionType::EmitSIB:
558+
case ActionType::EmitIRGen:
559+
case ActionType::EmitIR:
560+
case ActionType::EmitBC:
561+
case ActionType::EmitAssembly:
562+
case ActionType::EmitObject:
563+
case ActionType::EmitImportedModules:
564+
return false;
565+
}
566+
llvm_unreachable("unhandled action");
567+
}
528568
bool FrontendOptions::canActionEmitModule(ActionType action) {
529569
switch (action) {
530570
case ActionType::NoneAction:

lib/Frontend/ModuleInterfaceBuilder.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@ bool ModuleInterfaceBuilder::buildSwiftModuleInternal(
279279
if (SubInstance.getDiags().hadAnyError()) {
280280
return std::make_error_code(std::errc::not_supported);
281281
}
282+
if (!ABIDescriptorPath.empty()) {
283+
swift::ide::api::dumpModuleContent(Mod, ABIDescriptorPath, true);
284+
}
282285
return std::error_code();
283286
});
284287
}, ThreadStackSize);

lib/Frontend/ModuleInterfaceBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class ModuleInterfaceBuilder {
4141
const StringRef moduleName;
4242
const StringRef moduleCachePath;
4343
const StringRef prebuiltCachePath;
44+
const StringRef ABIDescriptorPath;
4445
const bool disableInterfaceFileLock;
4546
const SourceLoc diagnosticLoc;
4647
DependencyTracker *const dependencyTracker;
@@ -94,13 +95,15 @@ class ModuleInterfaceBuilder {
9495
StringRef moduleName,
9596
StringRef moduleCachePath,
9697
StringRef prebuiltCachePath,
98+
StringRef ABIDescriptorPath,
9799
bool disableInterfaceFileLock = false,
98100
SourceLoc diagnosticLoc = SourceLoc(),
99101
DependencyTracker *tracker = nullptr)
100102
: sourceMgr(sourceMgr), diags(diags),
101103
subASTDelegate(subASTDelegate),
102104
interfacePath(interfacePath), moduleName(moduleName),
103105
moduleCachePath(moduleCachePath), prebuiltCachePath(prebuiltCachePath),
106+
ABIDescriptorPath(ABIDescriptorPath),
104107
disableInterfaceFileLock(disableInterfaceFileLock),
105108
diagnosticLoc(diagnosticLoc), dependencyTracker(tracker) {}
106109

lib/Frontend/ModuleInterfaceLoader.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ class ModuleInterfaceLoaderImpl {
918918
// the genericSubInvocation we'll need to use to compute the cache paths.
919919
ModuleInterfaceBuilder builder(
920920
ctx.SourceMgr, ctx.Diags, astDelegate, interfacePath, moduleName, cacheDir,
921-
prebuiltCacheDir,
921+
prebuiltCacheDir, StringRef(),
922922
Opts.disableInterfaceLock, diagnosticLoc,
923923
dependencyTracker);
924924

@@ -1093,15 +1093,15 @@ bool ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface(
10931093
const SearchPathOptions &SearchPathOpts, const LangOptions &LangOpts,
10941094
const ClangImporterOptions &ClangOpts, StringRef CacheDir,
10951095
StringRef PrebuiltCacheDir, StringRef ModuleName, StringRef InPath,
1096-
StringRef OutPath, bool SerializeDependencyHashes,
1096+
StringRef OutPath, StringRef ABIOutputPath, bool SerializeDependencyHashes,
10971097
bool TrackSystemDependencies, ModuleInterfaceLoaderOptions LoaderOpts,
10981098
RequireOSSAModules_t RequireOSSAModules) {
10991099
InterfaceSubContextDelegateImpl astDelegate(
11001100
SourceMgr, Diags, SearchPathOpts, LangOpts, ClangOpts, LoaderOpts,
11011101
/*CreateCacheDirIfAbsent*/ true, CacheDir, PrebuiltCacheDir,
11021102
SerializeDependencyHashes, TrackSystemDependencies, RequireOSSAModules);
11031103
ModuleInterfaceBuilder builder(SourceMgr, Diags, astDelegate, InPath,
1104-
ModuleName, CacheDir, PrebuiltCacheDir,
1104+
ModuleName, CacheDir, PrebuiltCacheDir, ABIOutputPath,
11051105
LoaderOpts.disableInterfaceLock);
11061106
// FIXME: We really only want to serialize 'important' dependencies here, if
11071107
// we want to ship the built swiftmodules to another machine.

lib/FrontendTool/FrontendTool.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,12 +412,14 @@ static bool buildModuleFromInterface(CompilerInstance &Instance) {
412412
StringRef InputPath = FEOpts.InputsAndOutputs.getFilenameOfFirstInput();
413413
StringRef PrebuiltCachePath = FEOpts.PrebuiltModuleCachePath;
414414
ModuleInterfaceLoaderOptions LoaderOpts(FEOpts);
415+
StringRef ABIPath = Instance.getPrimarySpecificPathsForAtMostOnePrimary()
416+
.SupplementaryOutputs.ABIDescriptorOutputPath;
415417
return ModuleInterfaceLoader::buildSwiftModuleFromSwiftInterface(
416418
Instance.getSourceMgr(), Instance.getDiags(),
417419
Invocation.getSearchPathOptions(), Invocation.getLangOptions(),
418420
Invocation.getClangImporterOptions(),
419421
Invocation.getClangModuleCachePath(), PrebuiltCachePath,
420-
Invocation.getModuleName(), InputPath, Invocation.getOutputFilename(),
422+
Invocation.getModuleName(), InputPath, Invocation.getOutputFilename(), ABIPath,
421423
FEOpts.SerializeModuleInterfaceDependencyHashes,
422424
FEOpts.shouldTrackSystemDependencies(), LoaderOpts,
423425
RequireOSSAModules_t(Invocation.getSILOptions()));
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/Foo.swiftmodule)
3+
// RUN: %empty-directory(%t/ResourceDir/%target-sdk-name/prebuilt-modules/Foo.swiftmodule)
4+
// RUN: echo "public func foo() {}" > %t/Foo.swift
5+
6+
// RUN: %target-swift-frontend -emit-module %t/Foo.swift -module-name Foo -emit-module-interface-path %t/Foo.swiftinterface
7+
// RUN: %target-swift-frontend -compile-module-from-interface %t/Foo.swiftinterface -o %t/Foo.swiftmodule -module-name Foo -emit-abi-descriptor-path %t/Foo.json
8+
9+
// RUN: %FileCheck %s < %t/Foo.json
10+
11+
// CHECK: "kind": "Root"
12+
// CHECK-NEXT: "name": "TopLevel"
13+
// CHECK-NEXT: "printedName": "TopLevel"

0 commit comments

Comments
 (0)