From c4ba38ed1e33641c9db72823403b83dc7b8333e8 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Mon, 17 Dec 2007 06:36:45 +0000 Subject: [PATCH] Step #1 in adding headermap support to clang. llvm-svn: 45089 --- clang/Driver/clang.cpp | 63 +++++++++++++++-------- clang/Lex/HeaderSearch.cpp | 28 ++++++++++ clang/clang.xcodeproj/project.pbxproj | 2 + clang/include/clang/Lex/DirectoryLookup.h | 48 +++++++++++++---- clang/include/clang/Lex/HeaderMap.h | 37 +++++++++++++ clang/include/clang/Lex/HeaderSearch.h | 9 ++++ 6 files changed, 157 insertions(+), 30 deletions(-) create mode 100644 clang/include/clang/Lex/HeaderMap.h diff --git a/clang/Driver/clang.cpp b/clang/Driver/clang.cpp index 095eaaa6ca0a..4f6ea926d25d 100644 --- a/clang/Driver/clang.cpp +++ b/clang/Driver/clang.cpp @@ -613,8 +613,9 @@ static std::vector IncludeGroup[4]; /// static void AddPath(const std::string &Path, IncludeDirGroup Group, bool isCXXAware, bool isUserSupplied, - bool isFramework, FileManager &FM) { + bool isFramework, HeaderSearch &HS) { assert(!Path.empty() && "can't handle empty path here"); + FileManager &FM = HS.getFileMgr(); // Compute the actual path, taking into consideration -isysroot. llvm::SmallString<256> MappedPath; @@ -648,6 +649,25 @@ static void AddPath(const std::string &Path, IncludeDirGroup Group, return; } + // Check to see if this is an apple-style headermap. + if (const FileEntry *FE = FM.getFile(&MappedPath[0], + &MappedPath[0]+MappedPath.size())) { + std::string ErrorInfo; + const HeaderMap *HM = HS.CreateHeaderMap(FE, ErrorInfo); + if (HM) { + IncludeGroup[Group].push_back(DirectoryLookup(HM, Type, isUserSupplied, + isFramework)); + return; + } + + // If this looked like a headermap but was corrupted, emit that error, + // otherwise treat it as a missing directory. + if (!ErrorInfo.empty()) { + fprintf(stderr, "%s\n", ErrorInfo.c_str()); + return; + } + } + if (Verbose) fprintf(stderr, "ignoring nonexistent directory \"%s\"\n", Path.c_str()); } @@ -674,23 +694,23 @@ static void InitializeIncludePaths(HeaderSearch &Headers, FileManager &FM, const LangOptions &Lang) { // Handle -F... options. for (unsigned i = 0, e = F_dirs.size(); i != e; ++i) - AddPath(F_dirs[i], Angled, false, true, true, FM); + AddPath(F_dirs[i], Angled, false, true, true, Headers); // Handle -I... options. for (unsigned i = 0, e = I_dirs.size(); i != e; ++i) - AddPath(I_dirs[i], Angled, false, true, false, FM); + AddPath(I_dirs[i], Angled, false, true, false, Headers); // Handle -idirafter... options. for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i) - AddPath(idirafter_dirs[i], After, false, true, false, FM); + AddPath(idirafter_dirs[i], After, false, true, false, Headers); // Handle -iquote... options. for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i) - AddPath(iquote_dirs[i], Quoted, false, true, false, FM); + AddPath(iquote_dirs[i], Quoted, false, true, false, Headers); // Handle -isystem... options. for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i) - AddPath(isystem_dirs[i], System, false, true, false, FM); + AddPath(isystem_dirs[i], System, false, true, false, Headers); // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in // parallel, processing the values in order of occurance to get the right @@ -719,12 +739,12 @@ static void InitializeIncludePaths(HeaderSearch &Headers, FileManager &FM, iwithprefix_vals.getPosition(iwithprefix_idx) < iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) { AddPath(Prefix+iwithprefix_vals[iwithprefix_idx], - System, false, false, false, FM); + System, false, false, false, Headers); ++iwithprefix_idx; iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size(); } else { AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx], - Angled, false, false, false, FM); + Angled, false, false, false, Headers); ++iwithprefixbefore_idx; iwithprefixbefore_done = iwithprefixbefore_idx == iwithprefixbefore_vals.size(); @@ -739,34 +759,35 @@ static void InitializeIncludePaths(HeaderSearch &Headers, FileManager &FM, // FIXME: get these from the target? if (!nostdinc) { if (Lang.CPlusPlus) { - AddPath("/usr/include/c++/4.0.0", System, true, false, false, FM); + AddPath("/usr/include/c++/4.0.0", System, true, false, false, Headers); AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false, - false, FM); - AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false,FM); + false, Headers); + AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false, + Headers); } - AddPath("/usr/local/include", System, false, false, false, FM); + AddPath("/usr/local/include", System, false, false, false, Headers); // leopard AddPath("/usr/lib/gcc/i686-apple-darwin9/4.0.1/include", System, - false, false, false, FM); + false, false, false, Headers); AddPath("/usr/lib/gcc/powerpc-apple-darwin9/4.0.1/include", - System, false, false, false, FM); + System, false, false, false, Headers); AddPath("/usr/lib/gcc/powerpc-apple-darwin9/" "4.0.1/../../../../powerpc-apple-darwin0/include", - System, false, false, false, FM); + System, false, false, false, Headers); // tiger AddPath("/usr/lib/gcc/i686-apple-darwin8/4.0.1/include", System, - false, false, false, FM); + false, false, false, Headers); AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include", - System, false, false, false, FM); + System, false, false, false, Headers); AddPath("/usr/lib/gcc/powerpc-apple-darwin8/" "4.0.1/../../../../powerpc-apple-darwin8/include", - System, false, false, false, FM); + System, false, false, false, Headers); - AddPath("/usr/include", System, false, false, false, FM); - AddPath("/System/Library/Frameworks", System, true, false, true, FM); - AddPath("/Library/Frameworks", System, true, false, true, FM); + AddPath("/usr/include", System, false, false, false, Headers); + AddPath("/System/Library/Frameworks", System, true, false, true, Headers); + AddPath("/Library/Frameworks", System, true, false, true, Headers); } // Now that we have collected all of the include paths, merge them all diff --git a/clang/Lex/HeaderSearch.cpp b/clang/Lex/HeaderSearch.cpp index 719b9fb9c689..c91c4f9ba4e6 100644 --- a/clang/Lex/HeaderSearch.cpp +++ b/clang/Lex/HeaderSearch.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderMap.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/IdentifierTable.h" #include "llvm/System/Path.h" @@ -27,6 +28,12 @@ HeaderSearch::HeaderSearch(FileManager &FM) : FileMgr(FM), FrameworkMap(64) { NumFrameworkLookups = NumSubFrameworkLookups = 0; } +HeaderSearch::~HeaderSearch() { + // Delete headermaps. + for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) + delete HeaderMaps[i].second; +} + void HeaderSearch::PrintStats() { fprintf(stderr, "\n*** HeaderSearch Stats:\n"); fprintf(stderr, "%d files tracked.\n", (int)FileInfo.size()); @@ -49,6 +56,27 @@ void HeaderSearch::PrintStats() { fprintf(stderr, "%d subframework lookups.\n", NumSubFrameworkLookups); } +/// CreateHeaderMap - This method returns a HeaderMap for the specified +/// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. +const HeaderMap *HeaderSearch::CreateHeaderMap(const FileEntry *FE, + std::string &ErrorInfo) { + // We expect the number of headermaps to be small, and almost always empty. + // If it ever grows, use of a linear search should be reevaluated. + if (!HeaderMaps.empty()) { + for (unsigned i = 0, e = HeaderMaps.size(); i != e; ++i) + if (HeaderMaps[i].first == FE) + return HeaderMaps[i].second; + } + + if (const HeaderMap *HM = HeaderMap::Create(FE, ErrorInfo)) { + HeaderMaps.push_back(std::make_pair(FE, HM)); + return HM; + } + + return 0; +} + + //===----------------------------------------------------------------------===// // Header File Location. //===----------------------------------------------------------------------===// diff --git a/clang/clang.xcodeproj/project.pbxproj b/clang/clang.xcodeproj/project.pbxproj index 0b2d9fabb035..649d1fd09e4e 100644 --- a/clang/clang.xcodeproj/project.pbxproj +++ b/clang/clang.xcodeproj/project.pbxproj @@ -314,6 +314,7 @@ DE6951C60C4D1F5D00A5826B /* RecordLayout.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = RecordLayout.h; path = clang/AST/RecordLayout.h; sourceTree = ""; }; DE6954630C5121BD00A5826B /* Token.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Token.h; sourceTree = ""; }; DE704B250D0FBEBE009C7762 /* SemaDeclObjC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SemaDeclObjC.cpp; path = Sema/SemaDeclObjC.cpp; sourceTree = ""; }; + DE704BD10D1647E7009C7762 /* HeaderMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HeaderMap.h; sourceTree = ""; }; DE75ED280B044DC90020CF81 /* ASTContext.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ASTContext.h; path = clang/AST/ASTContext.h; sourceTree = ""; }; DE75EDF00B06880E0020CF81 /* Type.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = Type.cpp; path = AST/Type.cpp; sourceTree = ""; }; DE928B120C05659200231DA4 /* ModuleBuilder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleBuilder.cpp; path = CodeGen/ModuleBuilder.cpp; sourceTree = ""; }; @@ -684,6 +685,7 @@ isa = PBXGroup; children = ( DE3450D60AEB543100DBC861 /* DirectoryLookup.h */, + DE704BD10D1647E7009C7762 /* HeaderMap.h */, DE344AB70AE5DF6D00DBC861 /* HeaderSearch.h */, DED7D73B0A524295003AD0FB /* Lexer.h */, 1A869A6E0BA2164C008DA07A /* LiteralSupport.h */, diff --git a/clang/include/clang/Lex/DirectoryLookup.h b/clang/include/clang/Lex/DirectoryLookup.h index a1cfb0a340d0..817c1597bcb0 100644 --- a/clang/include/clang/Lex/DirectoryLookup.h +++ b/clang/include/clang/Lex/DirectoryLookup.h @@ -16,9 +16,13 @@ namespace clang { class DirectoryEntry; +class HeaderMap; -/// DirectoryLookup - This class is used to specify the search order for -/// directories in #include directives. +/// DirectoryLookup - This class represents one entry in the search list that +/// specifies the search order for directories in #include directives. It +/// represents either a directory or a 'headermap'. A headermap is just like a +/// directory, but it remaps its contents through an indirection table instead +/// of indexing a directory. class DirectoryLookup { public: enum DirType { @@ -26,10 +30,16 @@ public: SystemHeaderDir, ExternCSystemHeaderDir }; -private: - /// Dir - This is the actual directory that we're referring to. - /// - const DirectoryEntry *Dir; +private: + union { // This union is discriminated by isHeaderMap. + /// Dir - This is the actual directory that we're referring to. + /// + const DirectoryEntry *Dir; + + /// Map - This is the HeaderMap corresponding if the isHeaderMap field is + /// true. + const HeaderMap *Map; + } u; /// DirCharacteristic - The type of directory this is, one of the DirType enum /// values. @@ -42,15 +52,35 @@ private: /// Framework - True if this is a framework directory search-path. /// bool Framework : 1; + + /// isHeaderMap - True if the HeaderMap field is valid, false if the Dir field + /// is valid. + bool isHeaderMap : 1; public: + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'dir'. DirectoryLookup(const DirectoryEntry *dir, DirType DT, bool isUser, bool isFramework) - : Dir(dir), DirCharacteristic(DT), UserSupplied(isUser), - Framework(isFramework) {} + : DirCharacteristic(DT), UserSupplied(isUser), + Framework(isFramework), isHeaderMap(false) { + u.Dir = dir; + } + + /// DirectoryLookup ctor - Note that this ctor *does not take ownership* of + /// 'map'. + DirectoryLookup(const HeaderMap *map, DirType DT, bool isUser, bool isFWork) + : DirCharacteristic(DT), UserSupplied(isUser), Framework(isFWork), + isHeaderMap(true) { + u.Map = map; + } /// getDir - Return the directory that this entry refers to. /// - const DirectoryEntry *getDir() const { return Dir; } + const DirectoryEntry *getDir() const { return !isHeaderMap ? u.Dir : 0; } + + /// getHeaderMap - Return the directory that this entry refers to. + /// + const HeaderMap *getHeaderMap() const { return isHeaderMap ? u.Map : 0; } /// DirCharacteristic - The type of directory this is, one of the DirType enum /// values. diff --git a/clang/include/clang/Lex/HeaderMap.h b/clang/include/clang/Lex/HeaderMap.h new file mode 100644 index 000000000000..7c79fe0447d2 --- /dev/null +++ b/clang/include/clang/Lex/HeaderMap.h @@ -0,0 +1,37 @@ +//===--- HeaderMap.h - A file that acts like dir of symlinks ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file was developed by Chris Lattner and is distributed under +// the University of Illinois Open Source License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the HeaderMap interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LEX_HEADERMAP_H +#define LLVM_CLANG_LEX_HEADERMAP_H + +namespace clang { + +/// This class represents an Apple concept known as a 'header map'. To the +/// #include file resolution process, it basically acts like a directory of +/// symlinks to files. Its advantages are that it is dense and more efficient +/// to create and process than a directory of symlinks. +class HeaderMap { +public: + /// HeaderMap::Create - This attempts to load the specified file as a header + /// map. If it doesn't look like a HeaderMap, it gives up and returns null. + /// If it looks like a HeaderMap but is obviously corrupted, it puts a reason + /// into the string error argument and returns null. + static const HeaderMap *Create(const FileEntry *FE, std::string &ErrorInfo) { + // FIXME: woot! + return 0; + } +}; + +} // end namespace clang. + +#endif \ No newline at end of file diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 381c672aebf2..70f7d957ba36 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -81,12 +81,17 @@ class HeaderSearch { /// name like "Carbon" to the Carbon.framework directory. llvm::StringMap FrameworkMap; + /// HeaderMaps - This is a mapping from FileEntry -> HeaderMap, uniquing + /// headermaps. This vector owns the headermap. + std::vector > HeaderMaps; + // Various statistics we track for performance analysis. unsigned NumIncluded; unsigned NumMultiIncludeFileOptzn; unsigned NumFrameworkLookups, NumSubFrameworkLookups; public: HeaderSearch(FileManager &FM); + ~HeaderSearch(); FileManager &getFileMgr() const { return FileMgr; } @@ -166,6 +171,10 @@ public: getFileInfo(File).ControllingMacro = ControllingMacro; } + /// CreateHeaderMap - This method returns a HeaderMap for the specified + /// FileEntry, uniquing them through the the 'HeaderMaps' datastructure. + const HeaderMap *CreateHeaderMap(const FileEntry *FE, std::string &ErrorInfo); + void PrintStats(); private: const FileEntry *DoFrameworkLookup(const DirectoryEntry *Dir,