32
32
#include " llvm/ADT/StringRef.h"
33
33
#include " llvm/ADT/StringSet.h"
34
34
#include " llvm/Support/FileSystem.h"
35
+ #include " llvm/Support/StringSaver.h"
36
+ #include " llvm/Support/YAMLTraits.h"
37
+ #include " llvm/Support/YAMLParser.h"
35
38
#include < set>
36
39
37
40
using namespace swift ;
41
+ using namespace llvm ::yaml;
38
42
39
43
namespace {
44
+ struct BatchScanInput {
45
+ StringRef moduleName;
46
+ StringRef arguments;
47
+ StringRef outputPath;
48
+ };
49
+
50
+ static std::string getScalaNodeText (Node *N) {
51
+ SmallString<32 > Buffer;
52
+ return cast<ScalarNode>(N)->getValue (Buffer).str ();
53
+ }
54
+
55
+ // / Parse an entry like this, where the "platforms" key-value pair is optional:
56
+ // / {
57
+ // / "module": "Foo.pcm",
58
+ // / "arguments": "-target 10.15",
59
+ // / "output": "../Foo.json"
60
+ // / },
61
+ static bool parseBatchInputEntries (ASTContext &Ctx, llvm::StringSaver &saver,
62
+ Node *Node, std::vector<BatchScanInput> &result) {
63
+ auto *SN = cast<SequenceNode>(Node);
64
+ if (!SN)
65
+ return true ;
66
+ for (auto It = SN->begin (); It != SN->end (); ++It) {
67
+ auto *MN = cast<MappingNode>(&*It);
68
+ BatchScanInput entry;
69
+ Optional<std::set<int8_t >> Platforms;
70
+ for (auto &Pair: *MN) {
71
+ auto Key = getScalaNodeText (Pair.getKey ());
72
+ auto * Value = Pair.getValue ();
73
+ if (Key == " module" ) {
74
+ entry.moduleName = saver.save (getScalaNodeText (Value));
75
+ } else if (Key == " arguments" ) {
76
+ entry.arguments = saver.save (getScalaNodeText (Value));
77
+ } else if (Key == " output" ) {
78
+ entry.outputPath = saver.save (getScalaNodeText (Value));
79
+ } else {
80
+ // Future proof.
81
+ continue ;
82
+ }
83
+ }
84
+ if (entry.moduleName .empty ())
85
+ return true ;
86
+ if (entry.outputPath .empty ())
87
+ return true ;
88
+ auto ext = llvm::sys::path::extension (entry.moduleName );
89
+ if (ext != " .swiftmodule" && ext != " .pcm" )
90
+ return true ;
91
+ result.emplace_back (std::move (entry));
92
+ }
93
+ return false ;
94
+ }
40
95
96
+ static Optional<std::vector<BatchScanInput>>
97
+ parseBatchScanInputFile (ASTContext &ctx, StringRef batchInputPath,
98
+ llvm::StringSaver &saver) {
99
+ assert (!batchInputPath.empty ());
100
+ namespace yaml = llvm::yaml;
101
+ std::vector<BatchScanInput> result;
102
+
103
+ // Load the input file.
104
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> FileBufOrErr =
105
+ llvm::MemoryBuffer::getFile (batchInputPath);
106
+ if (!FileBufOrErr) {
107
+ ctx.Diags .diagnose (SourceLoc (), diag::batch_scan_input_file_missing,
108
+ batchInputPath);
109
+ return None;
110
+ }
111
+ StringRef Buffer = FileBufOrErr->get ()->getBuffer ();
112
+
113
+ // Use a new source manager instead of the one from ASTContext because we
114
+ // don't want the Json file to be persistent.
115
+ SourceManager SM;
116
+ yaml::Stream Stream (llvm::MemoryBufferRef (Buffer, batchInputPath),
117
+ SM.getLLVMSourceMgr ());
118
+ for (auto DI = Stream.begin (); DI != Stream.end (); ++ DI) {
119
+ assert (DI != Stream.end () && " Failed to read a document" );
120
+ yaml::Node *N = DI->getRoot ();
121
+ assert (N && " Failed to find a root" );
122
+ if (parseBatchInputEntries (ctx, saver, N, result)) {
123
+ ctx.Diags .diagnose (SourceLoc (), diag::batch_scan_input_file_corrupted,
124
+ batchInputPath);
125
+ return None;
126
+ }
127
+ }
128
+ return result;
129
+ }
41
130
}
42
131
43
132
// / Find all of the imported Clang modules starting with the given module name.
@@ -533,15 +622,17 @@ static bool diagnoseCycle(CompilerInstance &instance,
533
622
return false ;
534
623
}
535
624
536
- bool swift::scanClangDependencies (CompilerInstance &instance) {
625
+ static bool scanModuleDependencies (CompilerInstance &instance,
626
+ StringRef moduleName,
627
+ StringRef arguments,
628
+ bool isClang,
629
+ StringRef outputPath) {
537
630
ASTContext &ctx = instance.getASTContext ();
538
- ModuleDecl *mainModule = instance.getMainModule ();
539
631
auto &FEOpts = instance.getInvocation ().getFrontendOptions ();
540
632
ModuleInterfaceLoaderOptions LoaderOpts (FEOpts);
541
633
auto ModuleCachePath = getModuleCachePathFromClang (ctx
542
634
.getClangModuleLoader ()->getClangInstance ());
543
635
544
- StringRef mainModuleName = mainModule->getNameStr ();
545
636
llvm::SetVector<ModuleDependencyID, std::vector<ModuleDependencyID>,
546
637
std::set<ModuleDependencyID>> allModules;
547
638
// Create the module dependency cache.
@@ -555,16 +646,23 @@ bool swift::scanClangDependencies(CompilerInstance &instance) {
555
646
FEOpts.PrebuiltModuleCachePath ,
556
647
FEOpts.SerializeModuleInterfaceDependencyHashes ,
557
648
FEOpts.shouldTrackSystemDependencies ());
558
- // Loading the clang module using Clang importer.
559
- // This action will populate the cache with the main module's dependencies.
560
- auto rootDeps = static_cast <ClangImporter*>(ctx.getClangModuleLoader ())
561
- ->getModuleDependencies (mainModuleName, cache, ASTDelegate);
649
+ Optional<ModuleDependencies> rootDeps;
650
+ if (isClang) {
651
+ // Loading the clang module using Clang importer.
652
+ // This action will populate the cache with the main module's dependencies.
653
+ rootDeps = ctx.getModuleDependencies (moduleName, /* IsClang*/ true , cache,
654
+ ASTDelegate);
655
+ } else {
656
+ // Loading the swift module's dependencies.
657
+ rootDeps = ctx.getSwiftModuleDependencies (moduleName, cache, ASTDelegate);
658
+ }
562
659
if (!rootDeps.hasValue ()) {
563
660
// We cannot find the clang module, abort.
564
661
return true ;
565
662
}
566
663
// Add the main module.
567
- allModules.insert ({mainModuleName.str (), ModuleDependenciesKind::Clang});
664
+ allModules.insert ({moduleName.str (), isClang ? ModuleDependenciesKind::Clang:
665
+ ModuleDependenciesKind::Swift});
568
666
569
667
// Explore the dependencies of every module.
570
668
for (unsigned currentModuleIdx = 0 ;
@@ -576,13 +674,40 @@ bool swift::scanClangDependencies(CompilerInstance &instance) {
576
674
allModules.insert (discoveredModules.begin (), discoveredModules.end ());
577
675
}
578
676
// Write out the JSON description.
579
- std::string path = FEOpts.InputsAndOutputs .getSingleOutputFilename ();
580
677
std::error_code EC;
581
- llvm::raw_fd_ostream out (path , EC, llvm::sys::fs::F_None);
678
+ llvm::raw_fd_ostream out (outputPath , EC, llvm::sys::fs::F_None);
582
679
writeJSON (out, instance, cache, ASTDelegate, allModules.getArrayRef ());
583
680
return false ;
584
681
}
585
682
683
+ bool swift::scanClangDependencies (CompilerInstance &instance) {
684
+ return scanModuleDependencies (instance,
685
+ instance.getMainModule ()->getNameStr (),
686
+ StringRef (),
687
+ /* isClang*/ true ,
688
+ instance.getInvocation ().getFrontendOptions ()
689
+ .InputsAndOutputs .getSingleOutputFilename ());
690
+ }
691
+
692
+ bool swift::batchScanModuleDependencies (CompilerInstance &instance,
693
+ llvm::StringRef batchInputFile) {
694
+ (void )instance.getMainModule ();
695
+ llvm::BumpPtrAllocator alloc;
696
+ llvm::StringSaver saver (alloc);
697
+ auto results = parseBatchScanInputFile (instance.getASTContext (),
698
+ batchInputFile, saver);
699
+ if (!results.hasValue ())
700
+ return true ;
701
+ for (auto &entry: *results) {
702
+ auto moduleName = llvm::sys::path::stem (entry.moduleName );
703
+ auto isClang = llvm::sys::path::extension (entry.moduleName ) == " .pcm" ;
704
+ if (scanModuleDependencies (instance, moduleName, entry.arguments , isClang,
705
+ entry.outputPath ))
706
+ return true ;
707
+ }
708
+ return false ;
709
+ }
710
+
586
711
bool swift::scanDependencies (CompilerInstance &instance) {
587
712
ASTContext &Context = instance.getASTContext ();
588
713
ModuleDecl *mainModule = instance.getMainModule ();
0 commit comments