85
85
#include < deque>
86
86
#include < memory>
87
87
#include < unordered_set>
88
+ #include < utility>
88
89
89
90
#if !defined(_MSC_VER) && !defined(__MINGW32__)
90
91
#include < unistd.h>
@@ -184,73 +185,152 @@ static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
184
185
}
185
186
186
187
namespace {
188
+ struct SwiftModuleTraceInfo {
189
+ Identifier Name;
190
+ std::string Path;
191
+ bool IsImportedDirectly;
192
+ bool SupportsLibraryEvolution;
193
+ };
194
+
187
195
struct LoadedModuleTraceFormat {
188
- std::string Name;
196
+ static const unsigned CurrentVersion = 2 ;
197
+ unsigned Version;
198
+ Identifier Name;
189
199
std::string Arch;
190
- std::vector<std::string > SwiftModules;
200
+ std::vector<SwiftModuleTraceInfo > SwiftModules;
191
201
};
192
202
}
193
203
194
204
namespace swift {
195
205
namespace json {
206
+ template <> struct ObjectTraits <SwiftModuleTraceInfo> {
207
+ static void mapping (Output &out, SwiftModuleTraceInfo &contents) {
208
+ StringRef name = contents.Name .str ();
209
+ out.mapRequired (" name" , name);
210
+ out.mapRequired (" path" , contents.Path );
211
+ out.mapRequired (" isImportedDirectly" , contents.IsImportedDirectly );
212
+ out.mapRequired (" supportsLibraryEvolution" ,
213
+ contents.SupportsLibraryEvolution );
214
+ }
215
+ };
216
+
217
+ // Version notes:
218
+ // 1. Keys: name, arch, swiftmodules
219
+ // 2. New keys: version, swiftmodulesDetailedInfo
196
220
template <> struct ObjectTraits <LoadedModuleTraceFormat> {
197
221
static void mapping (Output &out, LoadedModuleTraceFormat &contents) {
198
- out.mapRequired (" name" , contents.Name );
222
+ out.mapRequired (" version" , contents.Version );
223
+
224
+ StringRef name = contents.Name .str ();
225
+ out.mapRequired (" name" , name);
226
+
199
227
out.mapRequired (" arch" , contents.Arch );
200
- out.mapRequired (" swiftmodules" , contents.SwiftModules );
228
+
229
+ // The 'swiftmodules' key is kept for backwards compatibility.
230
+ std::vector<std::string> moduleNames;
231
+ for (auto &m : contents.SwiftModules )
232
+ moduleNames.push_back (m.Path );
233
+ out.mapRequired (" swiftmodules" , moduleNames);
234
+
235
+ out.mapRequired (" swiftmodulesDetailedInfo" , contents.SwiftModules );
201
236
}
202
237
};
203
238
}
204
239
}
205
240
206
- static bool emitLoadedModuleTraceIfNeeded (ASTContext &ctxt ,
241
+ static bool emitLoadedModuleTraceIfNeeded (ModuleDecl *mainModule ,
207
242
DependencyTracker *depTracker,
208
- StringRef loadedModuleTracePath,
209
- StringRef moduleName) {
243
+ StringRef loadedModuleTracePath) {
210
244
if (loadedModuleTracePath.empty ())
211
245
return false ;
212
246
std::error_code EC;
213
247
llvm::raw_fd_ostream out (loadedModuleTracePath, EC, llvm::sys::fs::F_Append);
214
248
249
+ ASTContext &ctxt = mainModule->getASTContext ();
215
250
if (out.has_error () || EC) {
216
251
ctxt.Diags .diagnose (SourceLoc (), diag::error_opening_output,
217
252
loadedModuleTracePath, EC.message ());
218
253
out.clear_error ();
219
254
return true ;
220
255
}
221
256
222
- llvm::SmallVector<std::string, 16 > swiftModules;
257
+ ModuleDecl::ImportFilter filter = ModuleDecl::ImportFilterKind::Public;
258
+ filter |= ModuleDecl::ImportFilterKind::Private;
259
+ filter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
260
+ SmallVector<ModuleDecl::ImportedModule, 8 > imports;
261
+ mainModule->getImportedModules (imports, filter);
223
262
224
- // Canonicalise all the paths by opening them.
225
- for (auto &dep : depTracker->getDependencies ()) {
226
- llvm::SmallString<256 > buffer;
227
- StringRef realPath;
228
- int FD;
263
+ SmallPtrSet<ModuleDecl *, 8 > importedModules;
264
+ for (std::pair<ModuleDecl::AccessPathTy, ModuleDecl *> &import : imports)
265
+ importedModules.insert (import .second );
266
+
267
+ llvm::DenseMap<StringRef, ModuleDecl *> pathToModuleDecl;
268
+ for (auto &module : ctxt.LoadedModules ) {
269
+ ModuleDecl *loadedDecl = module .second ;
270
+ assert (loadedDecl && " Expected loaded module to be non-null." );
271
+ assert (!loadedDecl->getModuleFilename ().empty ()
272
+ && " Don't know how to handle modules with empty names." );
273
+ pathToModuleDecl.insert (
274
+ std::make_pair (loadedDecl->getModuleFilename (), loadedDecl));
275
+ }
276
+
277
+ std::vector<SwiftModuleTraceInfo> swiftModules;
278
+ SmallString<256 > buffer;
279
+ for (auto &depPath : depTracker->getDependencies ()) {
280
+ StringRef realDepPath;
229
281
// FIXME: appropriate error handling
230
- if (llvm::sys::fs::openFileForRead (dep, FD, llvm::sys::fs::OF_None,
231
- &buffer)) {
232
- // Couldn't open the file now, so let's just assume the old path was
282
+ if (llvm::sys::fs::real_path (depPath, buffer,/* expand_tilde=*/ true ))
283
+ // Couldn't find the canonical path, so let's just assume the old one was
233
284
// canonical (enough).
234
- realPath = dep;
235
- } else {
236
- realPath = buffer.str ();
237
- // Not much we can do about failing to close.
238
- (void )close (FD);
239
- }
285
+ realDepPath = depPath;
286
+ else
287
+ realDepPath = buffer.str ();
240
288
241
289
// Decide if this is a swiftmodule based on the extension of the raw
242
290
// dependency path, as the true file may have a different one.
243
- auto ext = llvm::sys::path::extension (dep);
244
- if (file_types::lookupTypeForExtension (ext) ==
245
- file_types::TY_SwiftModuleFile) {
246
- swiftModules.push_back (realPath);
291
+ // For example, this might happen when the canonicalized path points to
292
+ // a Content Addressed Storage (CAS) location.
293
+ auto moduleFileType =
294
+ file_types::lookupTypeForExtension (llvm::sys::path::extension (depPath));
295
+ if (moduleFileType == file_types::TY_SwiftModuleFile
296
+ || moduleFileType == file_types::TY_SwiftParseableInterfaceFile) {
297
+ auto dep = pathToModuleDecl.find (depPath);
298
+ assert (dep != pathToModuleDecl.end ()
299
+ && " Dependency must've been loaded." );
300
+ ModuleDecl *depMod = dep->second ;
301
+ swiftModules.push_back ({
302
+ /* Name=*/
303
+ depMod->getName (),
304
+ /* Path=*/
305
+ realDepPath,
306
+ // TODO: There is an edge case which is not handled here.
307
+ // When we build a framework using -import-underlying-module, or an
308
+ // app/test using -import-objc-header, we should look at the direct
309
+ // imports of the bridging modules, and mark those as our direct
310
+ // imports.
311
+ /* IsImportedDirectly=*/
312
+ importedModules.find (depMod) != importedModules.end (),
313
+ /* SupportsLibraryEvolution=*/
314
+ depMod->isResilient ()
315
+ });
247
316
}
248
317
}
249
318
319
+ // Almost a re-implementation of reversePathSortedFilenames :(.
320
+ std::sort (
321
+ swiftModules.begin (), swiftModules.end (),
322
+ [](const SwiftModuleTraceInfo &m1, const SwiftModuleTraceInfo &m2) -> bool {
323
+ return std::lexicographical_compare (
324
+ m1.Path .rbegin (), m1.Path .rend (),
325
+ m2.Path .rbegin (), m2.Path .rend ());
326
+ });
327
+
250
328
LoadedModuleTraceFormat trace = {
251
- /* name=*/ moduleName,
329
+ /* version=*/ LoadedModuleTraceFormat::CurrentVersion,
330
+ /* name=*/ mainModule->getName (),
252
331
/* arch=*/ ctxt.LangOpts .Target .getArchName (),
253
- /* swiftmodules=*/ reversePathSortedFilenames (swiftModules)};
332
+ swiftModules
333
+ };
254
334
255
335
// raw_fd_ostream is unbuffered, and we may have multiple processes writing,
256
336
// so first write the whole thing into memory and dump out that buffer to the
@@ -270,13 +350,13 @@ static bool emitLoadedModuleTraceIfNeeded(ASTContext &ctxt,
270
350
}
271
351
272
352
static bool
273
- emitLoadedModuleTraceForAllPrimariesIfNeeded (ASTContext &ctxt ,
353
+ emitLoadedModuleTraceForAllPrimariesIfNeeded (ModuleDecl *mainModule ,
274
354
DependencyTracker *depTracker,
275
355
const FrontendOptions &opts) {
276
356
return opts.InputsAndOutputs .forEachInputProducingSupplementaryOutput (
277
357
[&](const InputFile &input) -> bool {
278
358
return emitLoadedModuleTraceIfNeeded (
279
- ctxt , depTracker, input.loadedModuleTracePath (), opts. ModuleName );
359
+ mainModule , depTracker, input.loadedModuleTracePath ());
280
360
});
281
361
}
282
362
@@ -1007,7 +1087,7 @@ static bool performCompile(CompilerInstance &Instance,
1007
1087
emitReferenceDependenciesForAllPrimaryInputsIfNeeded (Invocation, Instance);
1008
1088
1009
1089
(void )emitLoadedModuleTraceForAllPrimariesIfNeeded (
1010
- Context , Instance.getDependencyTracker (), opts);
1090
+ Instance. getMainModule () , Instance.getDependencyTracker (), opts);
1011
1091
1012
1092
if (Context.hadError ()) {
1013
1093
// Emit the index store data even if there were compiler errors.
0 commit comments