@@ -237,12 +237,165 @@ template <> struct ObjectTraits<LoadedModuleTraceFormat> {
237
237
}
238
238
}
239
239
240
+ // / Compute the per-module information to be recorded in the trace file.
241
+ //
242
+ // The most interesting/tricky thing here is _which_ paths get recorded in
243
+ // the trace file as dependencies. It depends on how the module was synthesized.
244
+ // The key points are:
245
+ //
246
+ // 1. Paths to swiftmodules in the module cache or in the prebuilt cache are not
247
+ // recorded - Precondition: the corresponding path to the swiftinterface must
248
+ // already be present as a key in pathToModuleDecl.
249
+ // 2. swiftmodules next to a swiftinterface are saved if they are up-to-date.
250
+ //
251
+ // FIXME: Use the VFS instead of handling paths directly. We are particularly
252
+ // sloppy about handling relative paths in the dependency tracker.
253
+ static void computeSwiftModuleTraceInfo (
254
+ const SmallPtrSetImpl<ModuleDecl *> &importedModules,
255
+ const llvm::DenseMap<StringRef, ModuleDecl *> &pathToModuleDecl,
256
+ const DependencyTracker &depTracker,
257
+ StringRef prebuiltCachePath,
258
+ std::vector<SwiftModuleTraceInfo> &traceInfo) {
259
+
260
+ SmallString<256 > buffer;
261
+
262
+ std::string errMsg;
263
+ llvm::raw_string_ostream err (errMsg);
264
+
265
+ // FIXME: Use PrettyStackTrace instead.
266
+ auto errorUnexpectedPath =
267
+ [&pathToModuleDecl](llvm::raw_string_ostream &errStream) {
268
+ errStream << " The module <-> path mapping we have is:\n " ;
269
+ for (auto &m: pathToModuleDecl)
270
+ errStream << m.second ->getName () << " <-> " << m.first << ' \n ' ;
271
+ llvm::report_fatal_error (errStream.str ());
272
+ };
273
+
274
+ using namespace llvm ::sys;
275
+
276
+ auto computeAdjacentInterfacePath = [](SmallVectorImpl<char > &modPath) {
277
+ auto swiftInterfaceExt =
278
+ file_types::getExtension (file_types::TY_SwiftModuleInterfaceFile);
279
+ path::replace_extension (modPath, swiftInterfaceExt);
280
+ };
281
+
282
+ for (auto &depPath : depTracker.getDependencies ()) {
283
+
284
+ // Decide if this is a swiftmodule based on the extension of the raw
285
+ // dependency path, as the true file may have a different one.
286
+ // For example, this might happen when the canonicalized path points to
287
+ // a Content Addressed Storage (CAS) location.
288
+ auto moduleFileType =
289
+ file_types::lookupTypeForExtension (path::extension (depPath));
290
+ auto isSwiftmodule =
291
+ moduleFileType == file_types::TY_SwiftModuleFile;
292
+ auto isSwiftinterface =
293
+ moduleFileType == file_types::TY_SwiftModuleInterfaceFile;
294
+
295
+ if (!(isSwiftmodule || isSwiftinterface))
296
+ continue ;
297
+
298
+ auto dep = pathToModuleDecl.find (depPath);
299
+ if (dep != pathToModuleDecl.end ()) {
300
+ // Great, we recognize the path! Check if the file is still around.
301
+
302
+ ModuleDecl *depMod = dep->second ;
303
+ if (depMod->isResilient () && !isSwiftinterface) {
304
+ SmallString<256 > moduleAdjacentInterfacePath (depPath);
305
+ computeAdjacentInterfacePath (moduleAdjacentInterfacePath);
306
+ // FIXME: The behavior of fs::exists for relative paths is undocumented.
307
+ // Use something else instead?
308
+ if (!fs::exists (moduleAdjacentInterfacePath)) {
309
+ err << " The module " << depMod->getName ().str () << " has library"
310
+ << " evolution enabled but we're recording a non-adjacent"
311
+ << " swiftmodule at\n " << depPath << " \n in the trace." ;
312
+ llvm::report_fatal_error (err.str ());
313
+ }
314
+ buffer.clear ();
315
+ }
316
+
317
+ // FIXME: Better error handling
318
+ StringRef realDepPath
319
+ = fs::real_path (depPath, buffer, /* expand_tile*/ true )
320
+ ? StringRef (depPath) // Couldn't find the canonical path, assume
321
+ // this is good enough.
322
+ : buffer.str ();
323
+
324
+ traceInfo.push_back ({
325
+ /* Name=*/
326
+ depMod->getName (),
327
+ /* Path=*/
328
+ realDepPath,
329
+ // TODO: There is an edge case which is not handled here.
330
+ // When we build a framework using -import-underlying-module, or an
331
+ // app/test using -import-objc-header, we should look at the direct
332
+ // imports of the bridging modules, and mark those as our direct
333
+ // imports.
334
+ /* IsImportedDirectly=*/
335
+ importedModules.find (depMod) != importedModules.end (),
336
+ /* SupportsLibraryEvolution=*/
337
+ depMod->isResilient ()
338
+ });
339
+ buffer.clear ();
340
+
341
+ continue ;
342
+ }
343
+
344
+ // If the depTracker had an interface, that means that we must've
345
+ // built a swiftmodule from that interface, so we should have that
346
+ // filename available.
347
+ if (isSwiftinterface) {
348
+ err << " Unexpected path for swiftinterface file:\n " << depPath << " \n " ;
349
+ errorUnexpectedPath (err);
350
+ }
351
+
352
+ // Skip cached modules in the prebuilt cache. We will add the corresponding
353
+ // swiftinterface from the SDK directly, but this isn't checked. :-/
354
+ //
355
+ // FIXME: This is incorrect if both paths are not relative w.r.t. to the
356
+ // same root.
357
+ if (StringRef (depPath).startswith (prebuiltCachePath))
358
+ continue ;
359
+
360
+ // If we have a swiftmodule next to an interface, that interface path will
361
+ // be saved (not checked), so don't save the path to this swiftmodule.
362
+ SmallString<256 > moduleAdjacentInterfacePath (depPath);
363
+ computeAdjacentInterfacePath (moduleAdjacentInterfacePath);
364
+ if (pathToModuleDecl.find (moduleAdjacentInterfacePath)
365
+ != pathToModuleDecl.end ())
366
+ continue ;
367
+
368
+ // FIXME: The behavior of fs::exists for relative paths is undocumented.
369
+ // Use something else instead?
370
+ if (fs::exists (moduleAdjacentInterfacePath)) {
371
+ err << " Found swiftinterface at\n " << moduleAdjacentInterfacePath
372
+ << " \n but it was not recorded\n " ;
373
+ errorUnexpectedPath (err);
374
+ }
375
+ buffer.clear ();
376
+
377
+ err << " Don't know how to handle the dependency at:\n " << depPath
378
+ << " \n for module trace emission.\n " ;
379
+ errorUnexpectedPath (err);
380
+ }
381
+
382
+ // Almost a re-implementation of reversePathSortedFilenames :(.
383
+ std::sort (
384
+ traceInfo.begin (), traceInfo.end (),
385
+ [](const SwiftModuleTraceInfo &m1, const SwiftModuleTraceInfo &m2) -> bool {
386
+ return std::lexicographical_compare (
387
+ m1.Path .rbegin (), m1.Path .rend (),
388
+ m2.Path .rbegin (), m2.Path .rend ());
389
+ });
390
+ }
391
+
240
392
static bool emitLoadedModuleTraceIfNeeded (ModuleDecl *mainModule,
241
393
DependencyTracker *depTracker,
394
+ StringRef prebuiltCachePath,
242
395
StringRef loadedModuleTracePath) {
243
396
ASTContext &ctxt = mainModule->getASTContext ();
244
397
assert (!ctxt.hadError ()
245
- && " We may not be able to emit a proper trace if there was an error." );
398
+ && " We should've already exited earlier if there was an error." );
246
399
247
400
if (loadedModuleTracePath.empty ())
248
401
return false ;
@@ -269,67 +422,22 @@ static bool emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule,
269
422
llvm::DenseMap<StringRef, ModuleDecl *> pathToModuleDecl;
270
423
for (auto &module : ctxt.LoadedModules ) {
271
424
ModuleDecl *loadedDecl = module .second ;
272
- assert (loadedDecl && " Expected loaded module to be non-null." );
425
+ if (!loadedDecl)
426
+ llvm::report_fatal_error (" Expected loaded modules to be non-null." );
273
427
if (loadedDecl == mainModule)
274
428
continue ;
275
- assert (!loadedDecl->getModuleFilename ().empty ()
276
- && (" Don't know how to handle modules with empty names."
277
- " One potential reason for getting an empty module name might"
278
- " be that the module could not be deserialized correctly." ));
429
+ if (loadedDecl->getModuleFilename ().empty ())
430
+ llvm::report_fatal_error (
431
+ " Don't know how to handle modules with empty names."
432
+ " One potential reason for getting an empty module name might"
433
+ " be that the module could not be deserialized correctly." );
279
434
pathToModuleDecl.insert (
280
435
std::make_pair (loadedDecl->getModuleFilename (), loadedDecl));
281
436
}
282
437
283
438
std::vector<SwiftModuleTraceInfo> swiftModules;
284
- SmallString<256 > buffer;
285
- for (auto &depPath : depTracker->getDependencies ()) {
286
- StringRef realDepPath;
287
- // FIXME: appropriate error handling
288
- if (llvm::sys::fs::real_path (depPath, buffer,/* expand_tilde=*/ true ))
289
- // Couldn't find the canonical path, so let's just assume the old one was
290
- // canonical (enough).
291
- realDepPath = depPath;
292
- else
293
- realDepPath = buffer.str ();
294
-
295
- // Decide if this is a swiftmodule based on the extension of the raw
296
- // dependency path, as the true file may have a different one.
297
- // For example, this might happen when the canonicalized path points to
298
- // a Content Addressed Storage (CAS) location.
299
- auto moduleFileType =
300
- file_types::lookupTypeForExtension (llvm::sys::path::extension (depPath));
301
- if (moduleFileType == file_types::TY_SwiftModuleFile
302
- || moduleFileType == file_types::TY_SwiftModuleInterfaceFile) {
303
- auto dep = pathToModuleDecl.find (depPath);
304
- assert (dep != pathToModuleDecl.end ()
305
- && " Dependency must've been loaded." );
306
- ModuleDecl *depMod = dep->second ;
307
- swiftModules.push_back ({
308
- /* Name=*/
309
- depMod->getName (),
310
- /* Path=*/
311
- realDepPath,
312
- // TODO: There is an edge case which is not handled here.
313
- // When we build a framework using -import-underlying-module, or an
314
- // app/test using -import-objc-header, we should look at the direct
315
- // imports of the bridging modules, and mark those as our direct
316
- // imports.
317
- /* IsImportedDirectly=*/
318
- importedModules.find (depMod) != importedModules.end (),
319
- /* SupportsLibraryEvolution=*/
320
- depMod->isResilient ()
321
- });
322
- }
323
- }
324
-
325
- // Almost a re-implementation of reversePathSortedFilenames :(.
326
- std::sort (
327
- swiftModules.begin (), swiftModules.end (),
328
- [](const SwiftModuleTraceInfo &m1, const SwiftModuleTraceInfo &m2) -> bool {
329
- return std::lexicographical_compare (
330
- m1.Path .rbegin (), m1.Path .rend (),
331
- m2.Path .rbegin (), m2.Path .rend ());
332
- });
439
+ computeSwiftModuleTraceInfo (importedModules, pathToModuleDecl, *depTracker,
440
+ prebuiltCachePath, swiftModules);
333
441
334
442
LoadedModuleTraceFormat trace = {
335
443
/* version=*/ LoadedModuleTraceFormat::CurrentVersion,
@@ -339,8 +447,7 @@ static bool emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule,
339
447
};
340
448
341
449
// raw_fd_ostream is unbuffered, and we may have multiple processes writing,
342
- // so first write the whole thing into memory and dump out that buffer to the
343
- // file.
450
+ // so first write to memory and then dump the buffer to the trace file.
344
451
std::string stringBuffer;
345
452
{
346
453
llvm::raw_string_ostream memoryBuffer (stringBuffer);
@@ -349,7 +456,6 @@ static bool emitLoadedModuleTraceIfNeeded(ModuleDecl *mainModule,
349
456
json::jsonize (jsonOutput, trace, /* Required=*/ true );
350
457
}
351
458
stringBuffer += " \n " ;
352
-
353
459
out << stringBuffer;
354
460
355
461
return true ;
@@ -362,7 +468,8 @@ emitLoadedModuleTraceForAllPrimariesIfNeeded(ModuleDecl *mainModule,
362
468
return opts.InputsAndOutputs .forEachInputProducingSupplementaryOutput (
363
469
[&](const InputFile &input) -> bool {
364
470
return emitLoadedModuleTraceIfNeeded (
365
- mainModule, depTracker, input.loadedModuleTracePath ());
471
+ mainModule, depTracker, opts.PrebuiltModuleCachePath ,
472
+ input.loadedModuleTracePath ());
366
473
});
367
474
}
368
475
0 commit comments