diff options
author | Ben Langmuir <blangmuir@apple.com> | 2022-09-29 16:04:38 -0700 |
---|---|---|
committer | Ben Langmuir <blangmuir@apple.com> | 2022-10-05 15:42:38 -0700 |
commit | 074fcec1eabfc992c46c95df215b1caf5cf58970 (patch) | |
tree | 7fcfcd5cb3de12e4584a39ca6c951e956de64acf /clang/lib/Lex/ModuleMap.cpp | |
parent | ff7a2b60555a28754b9513b78c5a6b4678b6656f (diff) | |
download | llvm-074fcec1eabfc992c46c95df215b1caf5cf58970.zip llvm-074fcec1eabfc992c46c95df215b1caf5cf58970.tar.gz llvm-074fcec1eabfc992c46c95df215b1caf5cf58970.tar.bz2 |
[clang][deps] Canonicalize module map path
When dep-scanning, canonicalize the module map path as much as we can.
This avoids unnecessarily needing to build multiple versions of a module
due to symlinks or case-insensitive file paths.
Despite the name `tryGetRealPathName`, the previous implementation did
not actually return the realpath most of the time, and indeed it would
be incorrect to do so since the realpath could be outside the module
directory, which would have broken finding headers relative to the
module.
Instead, use a canonicalization that is specific to the needs of
modulemap files (canonicalize the directory separately from the
filename).
Differential Revision: https://reviews.llvm.org/D134923
Diffstat (limited to 'clang/lib/Lex/ModuleMap.cpp')
-rw-r--r-- | clang/lib/Lex/ModuleMap.cpp | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index dbb81dc..cbd3303f 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -1303,6 +1303,42 @@ void ModuleMap::setInferredModuleAllowedBy(Module *M, const FileEntry *ModMap) { InferredModuleAllowedBy[M] = ModMap; } +std::error_code +ModuleMap::canonicalizeModuleMapPath(SmallVectorImpl<char> &Path) { + StringRef Dir = llvm::sys::path::parent_path({Path.data(), Path.size()}); + + // Do not canonicalize within the framework; the module map parser expects + // Modules/ not Versions/A/Modules. + if (llvm::sys::path::filename(Dir) == "Modules") { + StringRef Parent = llvm::sys::path::parent_path(Dir); + if (Parent.endswith(".framework")) + Dir = Parent; + } + + FileManager &FM = SourceMgr.getFileManager(); + auto DirEntry = FM.getDirectory(Dir.empty() ? "." : Dir); + if (!DirEntry) + return DirEntry.getError(); + + // Canonicalize the directory. + StringRef CanonicalDir = FM.getCanonicalName(*DirEntry); + if (CanonicalDir != Dir) { + bool Done = llvm::sys::path::replace_path_prefix(Path, Dir, CanonicalDir); + (void)Done; + assert(Done && "Path should always start with Dir"); + } + + // In theory, the filename component should also be canonicalized if it + // on a case-insensitive filesystem. However, the extra canonicalization is + // expensive and if clang looked up the filename it will always be lowercase. + + // Remove ., remove redundant separators, and switch to native separators. + // This is needed for separators between CanonicalDir and the filename. + llvm::sys::path::remove_dots(Path); + + return std::error_code(); +} + void ModuleMap::addAdditionalModuleMapFile(const Module *M, const FileEntry *ModuleMap) { AdditionalModMaps[M].insert(ModuleMap); |