diff options
author | Douglas Gregor <dgregor@apple.com> | 2013-01-10 01:43:00 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2013-01-10 01:43:00 +0000 |
commit | 7005b907ea159c8e74e81f85269777429bc18d3c (patch) | |
tree | 8924bfcc156a1164176e9a3d9eca1eee045d4f30 /lib/Lex/HeaderSearch.cpp | |
parent | 880e538536d1a7597eb5805d67a08e3941577c7f (diff) |
Rework the realpath nonsense for framework lookups to deal more
uniformly with symlinks between top-level and embedded frameworks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172030 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Lex/HeaderSearch.cpp')
-rw-r--r-- | lib/Lex/HeaderSearch.cpp | 214 |
1 files changed, 117 insertions, 97 deletions
diff --git a/lib/Lex/HeaderSearch.cpp b/lib/Lex/HeaderSearch.cpp index cb68eb07e6..7363afc771 100644 --- a/lib/Lex/HeaderSearch.cpp +++ b/lib/Lex/HeaderSearch.cpp @@ -134,7 +134,7 @@ Module *HeaderSearch::lookupModule(StringRef ModuleName, bool AllowSearch) { 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 @@ const FileEntry *DirectoryLookup::LookupFile( 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 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( 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 @@ const FileEntry *DirectoryLookup::DoFrameworkLookup( 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 @@ Module *HeaderSearch::loadFrameworkModule(StringRef Name, 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. |