@@ -247,6 +247,32 @@ static Optional<llvm::vfs::Status> getStatusOfDependency(
247
247
return status.get ();
248
248
}
249
249
250
+ // / If the file dependency in \p FullDepPath is inside the \p Base directory,
251
+ // / this returns its path relative to \p Base. Otherwise it returns None.
252
+ static Optional<StringRef> getRelativeDepPath (StringRef DepPath,
253
+ StringRef Base) {
254
+ // If Base is the root directory, or DepPath does not start with Base, bail.
255
+ if (Base.size () <= 1 || !DepPath.startswith (Base)) {
256
+ return None;
257
+ }
258
+
259
+ assert (DepPath.size () > Base.size () &&
260
+ " should never depend on a directory" );
261
+
262
+ // Is the DepName something like ${Base}/foo.h"?
263
+ if (path::is_separator (DepPath[Base.size ()]))
264
+ return DepPath.substr (Base.size () + 1 );
265
+
266
+ // Is the DepName something like "${Base}foo.h", where Base
267
+ // itself contains a trailing slash?
268
+ if (path::is_separator (Base.back ()))
269
+ return DepPath.substr (Base.size ());
270
+
271
+ // We have something next to Base, like "Base.h", that's somehow
272
+ // become a dependency.
273
+ return None;
274
+ }
275
+
250
276
#pragma mark - Module Building
251
277
252
278
// / Builds a parseable module interface into a .swiftmodule at the provided
@@ -365,52 +391,33 @@ class swift::ParseableInterfaceBuilder {
365
391
bool collectDepsForSerialization (CompilerInstance &SubInstance,
366
392
SmallVectorImpl<FileDependency> &Deps,
367
393
bool IsHashBased) {
368
- StringRef SDKPath = SubInstance.getASTContext ().SearchPathOpts .SDKPath ;
369
- StringRef ResourcePath =
370
- SubInstance.getASTContext ().SearchPathOpts .RuntimeResourcePath ;
394
+ auto &Opts = SubInstance.getASTContext ().SearchPathOpts ;
395
+ SmallString<128 > SDKPath (Opts.SDKPath );
396
+ path::native (SDKPath);
397
+ SmallString<128 > ResourcePath (Opts.RuntimeResourcePath );
398
+ path::native (ResourcePath);
399
+
371
400
auto DTDeps = SubInstance.getDependencyTracker ()->getDependencies ();
372
401
SmallVector<StringRef, 16 > InitialDepNames (DTDeps.begin (), DTDeps.end ());
373
402
InitialDepNames.push_back (interfacePath);
374
403
llvm::StringSet<> AllDepNames;
404
+ SmallString<128 > Scratch;
405
+
406
+ for (const auto &InitialDepName : InitialDepNames) {
407
+ path::native (InitialDepName, Scratch);
408
+ StringRef DepName = Scratch.str ();
375
409
376
- for (auto const &DepName : InitialDepNames) {
377
410
assert (moduleCachePath.empty () || !DepName.startswith (moduleCachePath));
378
- assert (prebuiltCachePath.empty () || !DepName.startswith (prebuiltCachePath));
379
411
380
- // / Lazily load the dependency buffer if we need it. If we're not
381
- // / dealing with a hash-based dependencies, and if the dependency is
382
- // / not a .swiftmodule, we can avoid opening the buffer.
383
- std::unique_ptr<llvm::MemoryBuffer> DepBuf = nullptr ;
384
- auto getDepBuf = [&]() -> llvm::MemoryBuffer * {
385
- if (DepBuf) return DepBuf.get ();
386
- if (auto Buf = getBufferOfDependency (fs, DepName, interfacePath,
387
- diags, diagnosticLoc)) {
388
- DepBuf = std::move (Buf);
389
- return DepBuf.get ();
390
- }
391
- return nullptr ;
392
- };
412
+ // Serialize the paths of dependencies in the SDK relative to it.
413
+ Optional<StringRef> SDKRelativePath = getRelativeDepPath (DepName, SDKPath);
414
+ StringRef DepNameToStore = SDKRelativePath.getValueOr (DepName);
415
+ bool IsSDKRelative = SDKRelativePath.hasValue ();
393
416
394
- // Adjust the paths of dependences in the SDK to be relative to it
395
- bool IsSDKRelative = false ;
396
- StringRef DepNameToStore = DepName;
397
- if (SDKPath.size () > 1 && DepName.startswith (SDKPath)) {
398
- assert (DepName.size () > SDKPath.size () &&
399
- " should never depend on a directory" );
400
- if (llvm::sys::path::is_separator (DepName[SDKPath.size ()])) {
401
- // Is the DepName something like ${SDKPath}/foo.h"?
402
- DepNameToStore = DepName.substr (SDKPath.size () + 1 );
403
- IsSDKRelative = true ;
404
- } else if (llvm::sys::path::is_separator (SDKPath.back ())) {
405
- // Is the DepName something like "${SDKPath}foo.h", where SDKPath
406
- // itself contains a trailing slash?
407
- DepNameToStore = DepName.substr (SDKPath.size ());
408
- IsSDKRelative = true ;
409
- } else {
410
- // We have something next to an SDK, like "Foo.sdk.h", that's somehow
411
- // become a dependency.
412
- }
413
- }
417
+ // Forwarding modules add the underlying prebuilt module to their
418
+ // dependency list -- don't serialize that.
419
+ if (!prebuiltCachePath.empty () && DepName.startswith (prebuiltCachePath))
420
+ continue ;
414
421
415
422
if (AllDepNames.insert (DepName).second && dependencyTracker) {
416
423
dependencyTracker->addDependency (DepName, /* isSystem*/ IsSDKRelative);
@@ -425,6 +432,20 @@ class swift::ParseableInterfaceBuilder {
425
432
if (!Status)
426
433
return true ;
427
434
435
+ // / Lazily load the dependency buffer if we need it. If we're not
436
+ // / dealing with a hash-based dependencies, and if the dependency is
437
+ // / not a .swiftmodule, we can avoid opening the buffer.
438
+ std::unique_ptr<llvm::MemoryBuffer> DepBuf = nullptr ;
439
+ auto getDepBuf = [&]() -> llvm::MemoryBuffer * {
440
+ if (DepBuf) return DepBuf.get ();
441
+ if (auto Buf = getBufferOfDependency (fs, DepName, interfacePath,
442
+ diags, diagnosticLoc)) {
443
+ DepBuf = std::move (Buf);
444
+ return DepBuf.get ();
445
+ }
446
+ return nullptr ;
447
+ };
448
+
428
449
if (IsHashBased) {
429
450
auto buf = getDepBuf ();
430
451
if (!buf) return true ;
@@ -683,8 +704,7 @@ class ParseableInterfaceModuleLoaderImpl {
683
704
if (!dep.isSDKRelative ())
684
705
return dep.getPath ();
685
706
686
- StringRef SDKPath = ctx.SearchPathOpts .SDKPath ;
687
- scratch.assign (SDKPath.begin (), SDKPath.end ());
707
+ path::native (ctx.SearchPathOpts .SDKPath , scratch);
688
708
llvm::sys::path::append (scratch, dep.getPath ());
689
709
return StringRef (scratch.data (), scratch.size ());
690
710
}
@@ -812,6 +832,10 @@ class ParseableInterfaceModuleLoaderImpl {
812
832
}
813
833
path::append (scratch, path::filename (modulePath));
814
834
835
+ // If there isn't a file at this location, skip returning a path.
836
+ if (!fs.exists (scratch))
837
+ return None;
838
+
815
839
return scratch.str ();
816
840
}
817
841
@@ -898,7 +922,7 @@ class ParseableInterfaceModuleLoaderImpl {
898
922
return DiscoveredModule::prebuilt (*path, std::move (moduleBuffer));
899
923
} else {
900
924
LLVM_DEBUG (llvm::dbgs () << " Found out-of-date prebuilt module at "
901
- << modulePath << " \n " );
925
+ << path-> str () << " \n " );
902
926
}
903
927
}
904
928
}
@@ -935,40 +959,62 @@ class ParseableInterfaceModuleLoaderImpl {
935
959
936
960
// / Writes the "forwarding module" that will forward to a module in the
937
961
// / prebuilt cache.
962
+ // /
938
963
// / Since forwarding modules track dependencies separately from the module
939
964
// / they point to, we'll need to grab the up-to-date file status while doing
940
- // / this.
941
- bool writeForwardingModule (const DiscoveredModule &mod,
942
- StringRef outputPath,
943
- ArrayRef<FileDependency> deps) {
965
+ // / this. If the write was successful, it also updates the
966
+ // / list of dependencies to match what was written to the forwarding file.
967
+ bool writeForwardingModuleAndUpdateDeps (
968
+ const DiscoveredModule &mod, StringRef outputPath,
969
+ SmallVectorImpl<FileDependency> &deps) {
944
970
assert (mod.isPrebuilt () &&
945
971
" cannot write forwarding file for non-prebuilt module" );
946
972
ForwardingModule fwd (mod.path );
947
973
974
+ SmallVector<FileDependency, 16 > depsAdjustedToMTime;
975
+
948
976
// FIXME: We need to avoid re-statting all these dependencies, otherwise
949
977
// we may record out-of-date information.
950
- auto addDependency = [&](StringRef path) {
978
+ auto addDependency = [&](StringRef path) -> FileDependency {
951
979
auto status = fs.status (path);
952
980
uint64_t mtime =
953
981
status->getLastModificationTime ().time_since_epoch ().count ();
954
982
fwd.addDependency (path, status->getSize (), mtime);
983
+
984
+ // Construct new FileDependency matching what we've added to the
985
+ // forwarding module. This is no longer SDK-relative because the absolute
986
+ // path has already been resolved.
987
+ return FileDependency::modTimeBased (path, /* isSDKRelative*/ false ,
988
+ status->getSize (), mtime);
955
989
};
956
990
957
- // Add the prebuilt module as a dependency of the forwarding module.
958
- addDependency (fwd.underlyingModulePath );
991
+ // Add the prebuilt module as a dependency of the forwarding module, but
992
+ // don't add it to the outer dependency list.
993
+ (void )addDependency (fwd.underlyingModulePath );
959
994
960
- // Add all the dependencies from the prebuilt module.
995
+ // Add all the dependencies from the prebuilt module, and update our list
996
+ // of dependencies to reflect what's recorded in the forwarding module.
961
997
SmallString<128 > SDKRelativeBuffer;
962
998
for (auto dep : deps) {
963
- addDependency (getFullDependencyPath (dep, SDKRelativeBuffer));
999
+ auto adjustedDep =
1000
+ addDependency (getFullDependencyPath (dep, SDKRelativeBuffer));
1001
+ depsAdjustedToMTime.push_back (adjustedDep);
964
1002
}
965
1003
966
- return withOutputFile (diags, outputPath,
1004
+ auto hadError = withOutputFile (diags, outputPath,
967
1005
[&](llvm::raw_pwrite_stream &out) {
968
1006
llvm::yaml::Output yamlWriter (out);
969
1007
yamlWriter << fwd;
970
1008
return false ;
971
1009
});
1010
+
1011
+ if (hadError)
1012
+ return true ;
1013
+
1014
+ // If and only if we succeeded writing the forwarding file, update the
1015
+ // provided list of dependencies.
1016
+ deps = depsAdjustedToMTime;
1017
+ return false ;
972
1018
}
973
1019
974
1020
// / Looks up the best module to load for a given interface, and returns a
@@ -1017,17 +1063,20 @@ class ParseableInterfaceModuleLoaderImpl {
1017
1063
if (moduleOrErr) {
1018
1064
auto module = std::move (moduleOrErr.get ());
1019
1065
1020
- // If it's prebuilt, use this time to generate a forwarding module.
1066
+ // If it's prebuilt, use this time to generate a forwarding module and
1067
+ // update the dependencies to use modification times.
1021
1068
if (module .isPrebuilt ())
1022
- if (writeForwardingModule (module , cachedOutputPath, allDeps))
1069
+ if (writeForwardingModuleAndUpdateDeps (module , cachedOutputPath,
1070
+ allDeps))
1023
1071
return std::make_error_code (std::errc::not_supported);
1024
1072
1025
1073
// Report the module's dependencies to the dependencyTracker
1026
1074
if (dependencyTracker) {
1027
1075
SmallString<128 > SDKRelativeBuffer;
1028
1076
for (auto &dep: allDeps) {
1029
1077
StringRef fullPath = getFullDependencyPath (dep, SDKRelativeBuffer);
1030
- dependencyTracker->addDependency (fullPath, dep.isSDKRelative ());
1078
+ dependencyTracker->addDependency (fullPath,
1079
+ /* IsSystem=*/ dep.isSDKRelative ());
1031
1080
}
1032
1081
}
1033
1082
0 commit comments