[cfe-commits] r172030 - in /cfe/trunk: include/clang/Lex/ModuleMap.h lib/Lex/HeaderSearch.cpp lib/Lex/ModuleMap.cpp
Douglas Gregor
dgregor at apple.com
Wed Jan 9 17:43:01 PST 2013
Author: dgregor
Date: Wed Jan 9 19:43:00 2013
New Revision: 172030
URL: http://llvm.org/viewvc/llvm-project?rev=172030&view=rev
Log:
Rework the realpath nonsense for framework lookups to deal more
uniformly with symlinks between top-level and embedded frameworks.
Modified:
cfe/trunk/include/clang/Lex/ModuleMap.h
cfe/trunk/lib/Lex/HeaderSearch.cpp
cfe/trunk/lib/Lex/ModuleMap.cpp
Modified: cfe/trunk/include/clang/Lex/ModuleMap.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/ModuleMap.h?rev=172030&r1=172029&r2=172030&view=diff
==============================================================================
--- cfe/trunk/include/clang/Lex/ModuleMap.h (original)
+++ cfe/trunk/include/clang/Lex/ModuleMap.h Wed Jan 9 19:43:00 2013
@@ -111,6 +111,10 @@
/// framework modules from within those directories.
llvm::DenseMap<const DirectoryEntry *, InferredDirectory> InferredDirectories;
+ /// \brief Describes whether we haved parsed a particular file as a module
+ /// map.
+ llvm::DenseMap<const FileEntry *, bool> ParsedModuleMap;
+
friend class ModuleMapParser;
/// \brief Resolve the given export declaration into an actual export
Modified: cfe/trunk/lib/Lex/HeaderSearch.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/HeaderSearch.cpp?rev=172030&r1=172029&r2=172030&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/HeaderSearch.cpp (original)
+++ cfe/trunk/lib/Lex/HeaderSearch.cpp Wed Jan 9 19:43:00 2013
@@ -134,7 +134,7 @@
if (Module || !AllowSearch)
return Module;
- // Look through the various header search paths to load any avai;able module
+ // Look through the various header search paths to load any available module
// maps, searching for a module map that describes this module.
for (unsigned Idx = 0, N = SearchDirs.size(); Idx != N; ++Idx) {
if (SearchDirs[Idx].isFramework()) {
@@ -263,6 +263,60 @@
return Result;
}
+/// \brief Given a framework directory, find the top-most framework directory.
+///
+/// \param FileMgr The file manager to use for directory lookups.
+/// \param DirName The name of the framework directory.
+/// \param SubmodulePath Will be populated with the submodule path from the
+/// returned top-level module to the originally named framework.
+static const DirectoryEntry *
+getTopFrameworkDir(FileManager &FileMgr, StringRef DirName,
+ SmallVectorImpl<std::string> &SubmodulePath) {
+ assert(llvm::sys::path::extension(DirName) == ".framework" &&
+ "Not a framework directory");
+
+#ifdef LLVM_ON_UNIX
+ // Note: as an egregious but useful hack we use the real path here, because
+ // frameworks moving between top-level frameworks to embedded frameworks tend
+ // to be symlinked, and we base the logical structure of modules on the
+ // physical layout. In particular, we need to deal with crazy includes like
+ //
+ // #include <Foo/Frameworks/Bar.framework/Headers/Wibble.h>
+ //
+ // where 'Bar' used to be embedded in 'Foo', is now a top-level framework
+ // which one should access with, e.g.,
+ //
+ // #include <Bar/Wibble.h>
+ //
+ // Similar issues occur when a top-level framework has moved into an
+ // embedded framework.
+ char RealDirName[PATH_MAX];
+ if (realpath(DirName.str().c_str(), RealDirName))
+ DirName = RealDirName;
+#endif
+
+ const DirectoryEntry *TopFrameworkDir = FileMgr.getDirectory(DirName);
+ do {
+ // Get the parent directory name.
+ DirName = llvm::sys::path::parent_path(DirName);
+ if (DirName.empty())
+ break;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(DirName);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(DirName) == ".framework") {
+ SubmodulePath.push_back(llvm::sys::path::stem(DirName));
+ TopFrameworkDir = Dir;
+ }
+ } while (true);
+
+ return TopFrameworkDir;
+}
/// DoFrameworkLookup - Do a lookup of the specified file in the current
/// DirectoryLookup, which is a framework directory.
@@ -334,17 +388,6 @@
RelativePath->clear();
RelativePath->append(Filename.begin()+SlashPos+1, Filename.end());
}
-
- // If we're allowed to look for modules, try to load or create the module
- // corresponding to this framework.
- Module *Module = 0;
- if (SuggestedModule) {
- if (const DirectoryEntry *FrameworkDir
- = FileMgr.getDirectory(FrameworkName)) {
- bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
- Module = HS.loadFrameworkModule(ModuleName, FrameworkDir, IsSystem);
- }
- }
// Check "/System/Library/Frameworks/Cocoa.framework/Headers/file.h"
unsigned OrigSize = FrameworkName.size();
@@ -357,28 +400,64 @@
SearchPath->append(FrameworkName.begin(), FrameworkName.end()-1);
}
- // Determine whether this is the module we're building or not.
- bool AutomaticImport = Module;
FrameworkName.append(Filename.begin()+SlashPos+1, Filename.end());
- if (const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport)) {
- if (AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
- return FE;
+ const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
+ /*openFile=*/!SuggestedModule);
+ if (!FE) {
+ // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
+ const char *Private = "Private";
+ FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
+ Private+strlen(Private));
+ if (SearchPath != NULL)
+ SearchPath->insert(SearchPath->begin()+OrigSize, Private,
+ Private+strlen(Private));
+
+ FE = FileMgr.getFile(FrameworkName.str(), /*openFile=*/!SuggestedModule);
}
- // Check "/System/Library/Frameworks/Cocoa.framework/PrivateHeaders/file.h"
- const char *Private = "Private";
- FrameworkName.insert(FrameworkName.begin()+OrigSize, Private,
- Private+strlen(Private));
- if (SearchPath != NULL)
- SearchPath->insert(SearchPath->begin()+OrigSize, Private,
- Private+strlen(Private));
-
- const FileEntry *FE = FileMgr.getFile(FrameworkName.str(),
- /*openFile=*/!AutomaticImport);
- if (FE && AutomaticImport)
- *SuggestedModule = HS.findModuleForHeader(FE);
+ // If we found the header and are allowed to suggest a module, do so now.
+ if (FE && SuggestedModule) {
+ // Find the framework in which this header occurs.
+ StringRef FrameworkPath = FE->getName();
+ bool FoundFramework = false;
+ do {
+ // Get the parent directory name.
+ FrameworkPath = llvm::sys::path::parent_path(FrameworkPath);
+ if (FrameworkPath.empty())
+ break;
+
+ // Determine whether this directory exists.
+ const DirectoryEntry *Dir = FileMgr.getDirectory(FrameworkPath);
+ if (!Dir)
+ break;
+
+ // If this is a framework directory, then we're a subframework of this
+ // framework.
+ if (llvm::sys::path::extension(FrameworkPath) == ".framework") {
+ FoundFramework = true;
+ break;
+ }
+ } while (true);
+
+ if (FoundFramework) {
+ // Find the top-level framework based on this framework.
+ SmallVector<std::string, 4> SubmodulePath;
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, FrameworkPath, SubmodulePath);
+
+ // Determine the name of the top-level framework.
+ StringRef ModuleName = llvm::sys::path::stem(TopFrameworkDir->getName());
+
+ // Load this framework module. If that succeeds, find the suggested module
+ // for this header, if any.
+ bool IsSystem = getDirCharacteristic() != SrcMgr::C_User;
+ if (HS.loadFrameworkModule(ModuleName, TopFrameworkDir, IsSystem)) {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ } else {
+ *SuggestedModule = HS.findModuleForHeader(FE);
+ }
+ }
return FE;
}
@@ -898,80 +977,21 @@
return ModMap.findModule(Name);
}
- // The top-level framework directory, from which we'll infer a framework
- // module.
- const DirectoryEntry *TopFrameworkDir = Dir;
-
- // The path from the module we're actually looking for back to the top-level
- // framework name.
- llvm::SmallVector<StringRef, 2> SubmodulePath;
+ // Figure out the top-level framework directory and the submodule path from
+ // that top-level framework to the requested framework.
+ llvm::SmallVector<std::string, 2> SubmodulePath;
SubmodulePath.push_back(Name);
-
- // Walk the directory structure to find any enclosing frameworks.
-#ifdef LLVM_ON_UNIX
- // Note: as an egregious but useful hack we use the real path here, because
- // frameworks moving from top-level frameworks to embedded frameworks tend
- // to be symlinked from the top-level location to the embedded location,
- // and we need to resolve lookups as if we had found the embedded location.
- char RealDirName[PATH_MAX];
- StringRef DirName;
- if (realpath(Dir->getName(), RealDirName))
- DirName = RealDirName;
- else
- DirName = Dir->getName();
-#else
- StringRef DirName = Dir->getName();
-#endif
- do {
- // Get the parent directory name.
- DirName = llvm::sys::path::parent_path(DirName);
- if (DirName.empty())
- break;
-
- // Determine whether this directory exists.
- Dir = FileMgr.getDirectory(DirName);
- if (!Dir)
- break;
-
- // If this is a framework directory, then we're a subframework of this
- // framework.
- if (llvm::sys::path::extension(DirName) == ".framework") {
- SubmodulePath.push_back(llvm::sys::path::stem(DirName));
- TopFrameworkDir = Dir;
- }
- } while (true);
-
- // Determine whether we're allowed to infer a module map.
- bool canInfer = false;
- if (llvm::sys::path::has_parent_path(TopFrameworkDir->getName())) {
- // Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(TopFrameworkDir->getName());
- if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
- // If there's a module map file in the parent directory, it can
- // explicitly allow us to infer framework modules.
- switch (loadModuleMapFile(ParentDir)) {
- case LMM_AlreadyLoaded:
- case LMM_NewlyLoaded: {
- StringRef Name = llvm::sys::path::stem(TopFrameworkDir->getName());
- canInfer = ModMap.canInferFrameworkModule(ParentDir, Name, IsSystem);
- break;
- }
- case LMM_InvalidModuleMap:
- case LMM_NoDirectory:
- break;
- }
- }
- }
+ const DirectoryEntry *TopFrameworkDir
+ = ::getTopFrameworkDir(FileMgr, Dir->getName(), SubmodulePath);
- // If we're not allowed to infer a module map, we're done.
- if (!canInfer)
- return 0;
// Try to infer a module map from the top-level framework directory.
Module *Result = ModMap.inferFrameworkModule(SubmodulePath.back(),
TopFrameworkDir,
IsSystem,
/*Parent=*/0);
+ if (!Result)
+ return 0;
// Follow the submodule path to find the requested (sub)framework module
// within the top-level framework module.
Modified: cfe/trunk/lib/Lex/ModuleMap.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/ModuleMap.cpp?rev=172030&r1=172029&r2=172030&view=diff
==============================================================================
--- cfe/trunk/lib/Lex/ModuleMap.cpp (original)
+++ cfe/trunk/lib/Lex/ModuleMap.cpp Wed Jan 9 19:43:00 2013
@@ -397,10 +397,22 @@
// If the framework has a parent path from which we're allowed to infer
// a framework module, do so.
if (!Parent) {
+ // Determine whether we're allowed to infer a module map.
+ StringRef FrameworkDirName = FrameworkDir->getName();
+#ifdef LLVM_ON_UNIX
+ // Note: as an egregious but useful hack we use the real path here, because
+ // we might be looking at an embedded framework that symlinks out to a
+ // top-level framework, and we need to infer as if we were naming the
+ // top-level framework.
+ char RealFrameworkDirName[PATH_MAX];
+ if (realpath(FrameworkDir->getName(), RealFrameworkDirName))
+ FrameworkDirName = RealFrameworkDirName;
+#endif
+
bool canInfer = false;
- if (llvm::sys::path::has_parent_path(FrameworkDir->getName())) {
+ if (llvm::sys::path::has_parent_path(FrameworkDirName)) {
// Figure out the parent path.
- StringRef Parent = llvm::sys::path::parent_path(FrameworkDir->getName());
+ StringRef Parent = llvm::sys::path::parent_path(FrameworkDirName);
if (const DirectoryEntry *ParentDir = FileMgr.getDirectory(Parent)) {
// Check whether we have already looked into the parent directory
// for a module map.
@@ -424,7 +436,7 @@
if (inferred->second.InferModules) {
// We're allowed to infer for this directory, but make sure it's okay
// to infer this particular module.
- StringRef Name = llvm::sys::path::filename(FrameworkDir->getName());
+ StringRef Name = llvm::sys::path::stem(FrameworkDirName);
canInfer = std::find(inferred->second.ExcludedModules.begin(),
inferred->second.ExcludedModules.end(),
Name) == inferred->second.ExcludedModules.end();
@@ -1692,11 +1704,16 @@
}
bool ModuleMap::parseModuleMapFile(const FileEntry *File) {
+ llvm::DenseMap<const FileEntry *, bool>::iterator Known
+ = ParsedModuleMap.find(File);
+ if (Known != ParsedModuleMap.end())
+ return Known->second;
+
assert(Target != 0 && "Missing target information");
FileID ID = SourceMgr->createFileID(File, SourceLocation(), SrcMgr::C_User);
const llvm::MemoryBuffer *Buffer = SourceMgr->getBuffer(ID);
if (!Buffer)
- return true;
+ return ParsedModuleMap[File] = true;
// Parse this module map file.
Lexer L(ID, SourceMgr->getBuffer(ID), *SourceMgr, MMapLangOpts);
@@ -1705,6 +1722,6 @@
BuiltinIncludeDir);
bool Result = Parser.parseModuleMapFile();
Diags->getClient()->EndSourceFile();
-
+ ParsedModuleMap[File] = Result;
return Result;
}
More information about the cfe-commits
mailing list