Skip to content

Commit 12c356b

Browse files
authored
Merge pull request swiftlang#34028 from artemcm/dependencies-prescan
[Dependency Scanner] Add option to execute an import prescan
2 parents 6aa0572 + d5449bf commit 12c356b

File tree

7 files changed

+92
-3
lines changed

7 files changed

+92
-3
lines changed

include/swift/Frontend/FrontendOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ class FrontendOptions {
272272
/// built and given to the compiler invocation.
273273
bool DisableImplicitModules = false;
274274

275+
/// When performing a dependency scanning action, only identify and output all imports
276+
/// of the main Swift module's source files.
277+
bool ImportPrescan = false;
278+
275279
/// The different modes for validating TBD against the LLVM IR.
276280
enum class TBDValidationMode {
277281
Default, ///< Do the default validation for the current platform.

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,11 @@ def placeholder_dependency_module_map
226226
def batch_scan_input_file
227227
: Separate<["-"], "batch-scan-input-file">, MetaVarName<"<path>">,
228228
HelpText<"Specify a JSON file containing modules to perform batch dependencies scanning">;
229-
}
230229

230+
def import_prescan : Flag<["-"], "import-prescan">,
231+
HelpText<"When performing a dependency scan, only dentify all imports of the main Swift module sources">;
232+
233+
}
231234

232235
// HIDDEN FLAGS
233236
let Flags = [FrontendOption, NoDriverOption, HelpHidden] in {

lib/Driver/Driver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,15 @@ static void validateDependencyScanningArgs(DiagnosticEngine &diags,
167167
const ArgList &args) {
168168
const Arg *ExternalDependencyMap = args.getLastArg(options::OPT_placeholder_dependency_module_map);
169169
const Arg *ScanDependencies = args.getLastArg(options::OPT_scan_dependencies);
170+
const Arg *Prescan = args.getLastArg(options::OPT_import_prescan);
170171
if (ExternalDependencyMap && !ScanDependencies) {
171172
diags.diagnose(SourceLoc(), diag::error_requirement_not_met,
172173
"-placeholder-dependency-module-map-file", "-scan-dependencies");
173174
}
175+
if (Prescan && !ScanDependencies) {
176+
diags.diagnose(SourceLoc(), diag::error_requirement_not_met,
177+
"-import-prescan", "-scan-dependencies");
178+
}
174179
}
175180

176181
static void validateDebugInfoArgs(DiagnosticEngine &diags,

lib/Frontend/ArgsToFrontendOptionsConverter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ bool ArgsToFrontendOptionsConverter::convert(
9090

9191
Opts.DisableImplicitModules |= Args.hasArg(OPT_disable_implicit_swift_modules);
9292

93+
Opts.ImportPrescan |= Args.hasArg(OPT_import_prescan);
94+
9395
// Always track system dependencies when scanning dependencies.
9496
if (const Arg *ModeArg = Args.getLastArg(OPT_modes_Group)) {
9597
if (ModeArg->getOption().matches(OPT_scan_dependencies)) {

lib/FrontendTool/ScanDependencies.cpp

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,17 @@ namespace {
387387
}
388388
}
389389

390+
static void writePrescanJSON(llvm::raw_ostream &out,
391+
const ModuleDependencies &mainModuleDependencies) {
392+
// Write out a JSON containing all main module imports.
393+
out << "{\n";
394+
SWIFT_DEFER {
395+
out << "}\n";
396+
};
397+
398+
writeJSONSingleField(out, "imports", mainModuleDependencies.getModuleDependencies(), 0, false);
399+
}
400+
390401
static void writeJSON(llvm::raw_ostream &out,
391402
CompilerInstance &instance,
392403
ModuleDependenciesCache &cache,
@@ -648,6 +659,8 @@ static bool scanModuleDependencies(CompilerInstance &instance,
648659
FEOpts.PrebuiltModuleCachePath,
649660
FEOpts.SerializeModuleInterfaceDependencyHashes,
650661
FEOpts.shouldTrackSystemDependencies());
662+
std::error_code EC;
663+
llvm::raw_fd_ostream out(outputPath, EC, llvm::sys::fs::F_None);
651664
Optional<ModuleDependencies> rootDeps;
652665
if (isClang) {
653666
// Loading the clang module using Clang importer.
@@ -666,6 +679,12 @@ static bool scanModuleDependencies(CompilerInstance &instance,
666679
allModules.insert({moduleName.str(), isClang ? ModuleDependenciesKind::Clang:
667680
ModuleDependenciesKind::Swift});
668681

682+
// Output module prescan.
683+
if (FEOpts.ImportPrescan) {
684+
writePrescanJSON(out, rootDeps.getValue());
685+
return false;
686+
}
687+
669688
// Explore the dependencies of every module.
670689
for (unsigned currentModuleIdx = 0;
671690
currentModuleIdx < allModules.size();
@@ -676,8 +695,6 @@ static bool scanModuleDependencies(CompilerInstance &instance,
676695
allModules.insert(discoveredModules.begin(), discoveredModules.end());
677696
}
678697
// Write out the JSON description.
679-
std::error_code EC;
680-
llvm::raw_fd_ostream out(outputPath, EC, llvm::sys::fs::F_None);
681698
writeJSON(out, instance, cache, ASTDelegate, allModules.getArrayRef());
682699
return false;
683700
}
@@ -774,6 +791,8 @@ bool swift::scanDependencies(CompilerInstance &instance) {
774791
"-Xcc", "-target", "-Xcc", instance.getASTContext().LangOpts.Target.str(),
775792
"-Xcc", apinotesVer
776793
});
794+
795+
// Compute Implicit dependencies of the main module
777796
{
778797
llvm::StringSet<> alreadyAddedModules;
779798
for (auto fileUnit : mainModule->getFiles()) {
@@ -820,6 +839,17 @@ bool swift::scanDependencies(CompilerInstance &instance) {
820839
}
821840
}
822841

842+
// If import-prescan is specified, discover and serialize main module dependencies only and exit.
843+
if (opts.ImportPrescan) {
844+
writePrescanJSON(out, mainDependencies);
845+
// This process succeeds regardless of whether any errors occurred.
846+
// FIXME: We shouldn't need this, but it's masking bugs in our scanning
847+
// logic where we don't create a fresh context when scanning Swift interfaces
848+
// that includes their own command-line flags.
849+
Context.Diags.resetHadAnyError();
850+
return false;
851+
}
852+
823853
// Add the main module.
824854
StringRef mainModuleName = mainModule->getNameStr();
825855
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/inputs)
3+
// RUN: %empty-directory(%t/outputs)
4+
// RUN: mkdir -p %t/clang-module-cache
5+
6+
// RUN: echo "[{" > %/t/inputs/input.json
7+
// RUN: echo "\"swiftModuleName\": \"F\"," >> %/t/inputs/input.json
8+
// RUN: echo "\"arguments\": \"-target x86_64-apple-macosx10.9\"," >> %/t/inputs/input.json
9+
// RUN: echo "\"output\": \"%/t/outputs/F.swiftmodule.json\"" >> %/t/inputs/input.json
10+
// RUN: echo "}]" >> %/t/inputs/input.json
11+
12+
// RUN: %target-swift-frontend -scan-dependencies -import-prescan -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4 -batch-scan-input-file %/t/inputs/input.json
13+
14+
// Check the contents of the JSON output
15+
// RUN: %FileCheck %s -check-prefix=CHECK-SWIFT < %t/outputs/F.swiftmodule.json
16+
17+
// CHECK-SWIFT: {
18+
// CHECK-SWIFT-NEXT:"imports": [
19+
// CHECK-SWIFT-NEXT: "Swift",
20+
// CHECK-SWIFT-NEXT: "F",
21+
// CHECK-SWIFT-NEXT: "SwiftOnoneSupport"
22+
// CHECK-SWIFT-NEXT:]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: mkdir -p %t/clang-module-cache
3+
// RUN: %target-swift-frontend -scan-dependencies -import-prescan -module-cache-path %t/clang-module-cache %s -o %t/deps.json -I %S/Inputs/CHeaders -I %S/Inputs/Swift -emit-dependencies -emit-dependencies-path %t/deps.d -import-objc-header %S/Inputs/CHeaders/Bridging.h -swift-version 4
4+
5+
// Check the contents of the JSON output
6+
// RUN: %FileCheck %s < %t/deps.json
7+
8+
// REQUIRES: executable_test
9+
// REQUIRES: objc_interop
10+
11+
import C
12+
import E
13+
import G
14+
import SubE
15+
16+
// CHECK: "imports": [
17+
// CHECK-NEXT: "C",
18+
// CHECK-NEXT: "E",
19+
// CHECK-NEXT: "G",
20+
// CHECK-NEXT: "SubE",
21+
// CHECK-NEXT: "Swift",
22+
// CHECK-NEXT: "SwiftOnoneSupport"
23+
// CHECK-NEXT: ]

0 commit comments

Comments
 (0)