]> granicus.if.org Git - clang/commitdiff
Move most of HeaderSearch initialization to libDriver.
authorNico Weber <nicolasweber@gmx.de>
Fri, 22 Aug 2008 09:25:22 +0000 (09:25 +0000)
committerNico Weber <nicolasweber@gmx.de>
Fri, 22 Aug 2008 09:25:22 +0000 (09:25 +0000)
For example, adding the default system include paths in clients is now as
simple as

  InitHeaderSearch init(headers);
  init.AddDefaultSystemIncludePaths(langopts);
  init.Realize();

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@55174 91177308-0d34-0410-b5e6-96231b3b80d8

Driver/clang.cpp
include/clang/Driver/InitHeaderSearch.h [new file with mode: 0644]
lib/Driver/InitHeaderSearch.cpp [new file with mode: 0644]

index 089faf1255567f933c7f32aa952adc96a7db8e08..c271f51233615d44dc61d8bebc76a431378f619d 100644 (file)
@@ -25,6 +25,7 @@
 #include "clang.h"
 #include "ASTConsumers.h"
 #include "HTMLDiagnostics.h"
+#include "clang/Driver/InitHeaderSearch.h"
 #include "clang/Driver/TextDiagnosticBuffer.h"
 #include "clang/Driver/TextDiagnosticPrinter.h"
 #include "clang/Analysis/PathDiagnostic.h"
@@ -757,170 +758,43 @@ isysroot("isysroot", llvm::cl::value_desc("dir"), llvm::cl::init("/"),
          llvm::cl::desc("Set the system root directory (usually /)"));
 
 // Finally, implement the code that groks the options above.
-enum IncludeDirGroup {
-  Quoted = 0,
-  Angled,
-  System,
-  After
-};
-
-static std::vector<DirectoryLookup> IncludeGroup[4];
-
-/// AddPath - Add the specified path to the specified group list.
-///
-static void AddPath(const std::string &Path, IncludeDirGroup Group,
-                    bool isCXXAware, bool isUserSupplied,
-                    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;
-  
-  // Handle isysroot.
-  if (Group == System) {
-    // FIXME: Portability.  This should be a sys::Path interface, this doesn't
-    // handle things like C:\ right, nor win32 \\network\device\blah.
-    if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
-      MappedPath.append(isysroot.begin(), isysroot.end());
-  }
-  
-  MappedPath.append(Path.begin(), Path.end());
-
-  // Compute the DirectoryLookup type.
-  DirectoryLookup::DirType Type;
-  if (Group == Quoted || Group == Angled)
-    Type = DirectoryLookup::NormalHeaderDir;
-  else if (isCXXAware)
-    Type = DirectoryLookup::SystemHeaderDir;
-  else
-    Type = DirectoryLookup::ExternCSystemHeaderDir;
-  
-  
-  // If the directory exists, add it.
-  if (const DirectoryEntry *DE = FM.getDirectory(&MappedPath[0], 
-                                                 &MappedPath[0]+
-                                                 MappedPath.size())) {
-    IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
-                                                  isFramework));
-    return;
-  }
-  
-  // Check to see if this is an apple-style headermap (which are not allowed to
-  // be frameworks).
-  if (!isFramework) {
-    if (const FileEntry *FE = FM.getFile(&MappedPath[0], 
-                                         &MappedPath[0]+MappedPath.size())) {
-      if (const HeaderMap *HM = HS.CreateHeaderMap(FE)) {
-        // It is a headermap, add it to the search path.
-        IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
-        return;
-      }
-    }
-  }
-  
-  if (Verbose)
-    fprintf(stderr, "ignoring nonexistent directory \"%s\"\n", Path.c_str());
-}
-
-/// RemoveDuplicates - If there are duplicate directory entries in the specified
-/// search list, remove the later (dead) ones.
-static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList) {
-  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
-  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
-  llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
-  for (unsigned i = 0; i != SearchList.size(); ++i) {
-    if (SearchList[i].isNormalDir()) {
-      // If this isn't the first time we've seen this dir, remove it.
-      if (SeenDirs.insert(SearchList[i].getDir()))
-        continue;
-      
-      if (Verbose)
-        fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
-                SearchList[i].getDir()->getName());
-    } else if (SearchList[i].isFramework()) {
-      // If this isn't the first time we've seen this framework dir, remove it.
-      if (SeenFrameworkDirs.insert(SearchList[i].getFrameworkDir()))
-        continue;
-      
-      if (Verbose)
-        fprintf(stderr, "ignoring duplicate framework \"%s\"\n",
-                SearchList[i].getFrameworkDir()->getName());
-      
-    } else {
-      assert(SearchList[i].isHeaderMap() && "Not a headermap or normal dir?");
-      // If this isn't the first time we've seen this headermap, remove it.
-      if (SeenHeaderMaps.insert(SearchList[i].getHeaderMap()))
-        continue;
-      
-      if (Verbose)
-        fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
-                SearchList[i].getDir()->getName());
-    }
-    
-    // This is reached if the current entry is a duplicate.
-    SearchList.erase(SearchList.begin()+i);
-    --i;
-  }
-}
-
-// AddEnvVarPaths - Add a list of paths from an environment variable to a
-// header search list.
-//
-static void AddEnvVarPaths(const char *Name, HeaderSearch &Headers) {
-  const char* at = getenv(Name);
-  if (!at)
-    return;
-
-  const char* delim = strchr(at, llvm::sys::PathSeparator);
-  while (delim != 0) {
-    if (delim-at == 0)
-      AddPath(".", Angled, false, true, false, Headers);
-    else
-      AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
-            true, false, Headers);
-    at = delim + 1;
-    delim = strchr(at, llvm::sys::PathSeparator);
-  }
-  if (*at == 0)
-    AddPath(".", Angled, false, true, false, Headers);
-  else
-    AddPath(at, Angled, false, true, false, Headers);
-}
 
 /// InitializeIncludePaths - Process the -I options and set them in the
 /// HeaderSearch object.
-static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
-                                   FileManager &FM, const LangOptions &Lang) {
+void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
+                            FileManager &FM, const LangOptions &Lang) {
+  InitHeaderSearch Init(Headers, Verbose, isysroot);
+
   // Handle -I... and -F... options, walking the lists in parallel.
   unsigned Iidx = 0, Fidx = 0;
   while (Iidx < I_dirs.size() && Fidx < F_dirs.size()) {
     if (I_dirs.getPosition(Iidx) < F_dirs.getPosition(Fidx)) {
-      AddPath(I_dirs[Iidx], Angled, false, true, false, Headers);
+      Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
       ++Iidx;
     } else {
-      AddPath(F_dirs[Fidx], Angled, false, true, true, Headers);
+      Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
       ++Fidx;
     }
   }
   
   // Consume what's left from whatever list was longer.
   for (; Iidx != I_dirs.size(); ++Iidx)
-    AddPath(I_dirs[Iidx], Angled, false, true, false, Headers);
+    Init.AddPath(I_dirs[Iidx], InitHeaderSearch::Angled, false, true, false);
   for (; Fidx != F_dirs.size(); ++Fidx)
-    AddPath(F_dirs[Fidx], Angled, false, true, true, Headers);
+    Init.AddPath(F_dirs[Fidx], InitHeaderSearch::Angled, false, true, true);
   
   // Handle -idirafter... options.
   for (unsigned i = 0, e = idirafter_dirs.size(); i != e; ++i)
-    AddPath(idirafter_dirs[i], After, false, true, false, Headers);
+    Init.AddPath(idirafter_dirs[i], InitHeaderSearch::After,
+        false, true, false);
   
   // Handle -iquote... options.
   for (unsigned i = 0, e = iquote_dirs.size(); i != e; ++i)
-    AddPath(iquote_dirs[i], Quoted, false, true, false, Headers);
+    Init.AddPath(iquote_dirs[i], InitHeaderSearch::Quoted, false, true, false);
   
   // Handle -isystem... options.
   for (unsigned i = 0, e = isystem_dirs.size(); i != e; ++i)
-    AddPath(isystem_dirs[i], System, false, true, false, Headers);
+    Init.AddPath(isystem_dirs[i], InitHeaderSearch::System, false, true, false);
 
   // Walk the -iprefix/-iwithprefix/-iwithprefixbefore argument lists in
   // parallel, processing the values in order of occurance to get the right
@@ -948,13 +822,13 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
                  (iwithprefixbefore_done || 
                   iwithprefix_vals.getPosition(iwithprefix_idx) < 
                   iwithprefixbefore_vals.getPosition(iwithprefixbefore_idx))) {
-        AddPath(Prefix+iwithprefix_vals[iwithprefix_idx], 
-                System, false, false, false, Headers);
+        Init.AddPath(Prefix+iwithprefix_vals[iwithprefix_idx], 
+                InitHeaderSearch::System, false, false, false);
         ++iwithprefix_idx;
         iwithprefix_done = iwithprefix_idx == iwithprefix_vals.size();
       } else {
-        AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx], 
-                Angled, false, false, false, Headers);
+        Init.AddPath(Prefix+iwithprefixbefore_vals[iwithprefixbefore_idx], 
+                InitHeaderSearch::Angled, false, false, false);
         ++iwithprefixbefore_idx;
         iwithprefixbefore_done = 
           iwithprefixbefore_idx == iwithprefixbefore_vals.size();
@@ -962,15 +836,7 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
     }
   }
 
-  AddEnvVarPaths("CPATH", Headers);
-  if (Lang.CPlusPlus && Lang.ObjC1)
-    AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH", Headers);
-  else if (Lang.CPlusPlus)
-    AddEnvVarPaths("CPLUS_INCLUDE_PATH", Headers);
-  else if (Lang.ObjC1)
-    AddEnvVarPaths("OBJC_INCLUDE_PATH", Headers);
-  else
-    AddEnvVarPaths("C_INCLUDE_PATH", Headers);
+  Init.AddDefaultEnvVarPaths(Lang);
 
   // Add the clang headers, which are relative to the clang driver.
   llvm::sys::Path MainExecutablePath = 
@@ -980,167 +846,17 @@ static void InitializeIncludePaths(const char *Argv0, HeaderSearch &Headers,
     MainExecutablePath.eraseComponent();  // Remove /clang from foo/bin/clang
     MainExecutablePath.eraseComponent();  // Remove /bin   from foo/bin
     MainExecutablePath.appendComponent("Headers"); // Get foo/Headers
-    AddPath(MainExecutablePath.c_str(), System, false, false, false, Headers);
+    Init.AddPath(MainExecutablePath.c_str(), InitHeaderSearch::System,
+        false, false, false);
   }
   
-  // FIXME: temporary hack: hard-coded paths.
-  // FIXME: get these from the target?
-  if (!nostdinc) {
-    if (Lang.CPlusPlus) {
-      AddPath("/usr/include/c++/4.2.1", System, true, false, false, Headers);
-      AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
-              false, Headers);
-      AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false,
-              Headers);
-
-      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, Headers);
-      AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false,
-              Headers);
-
-      // Ubuntu 7.10 - Gutsy Gibbon
-      AddPath("/usr/include/c++/4.1.3", System, true, false, false, Headers);
-      AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
-              false, Headers);
-      AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false,
-              Headers);
-
-      // Fedora 8
-      AddPath("/usr/include/c++/4.1.2", System, true, false, false, Headers);
-      AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
-              false, Headers);
-      AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false, 
-              Headers);
-
-      // Fedora 9
-      AddPath("/usr/include/c++/4.3.0", System, true, false, false, Headers);
-      AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
-              false, Headers);
-      AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false, 
-              Headers);
-
-      // Arch Linux 2008-06-24
-      AddPath("/usr/include/c++/4.3.1", System, true, false, false, Headers);
-      AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
-              false, Headers);
-      AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false,
-              Headers);
-      AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
-              false, false, Headers);
-    }
-    
-    AddPath("/usr/local/include", System, false, false, false, Headers);
-
-    AddPath("/usr/lib/gcc/i686-apple-darwin10/4.2.1/include", System, 
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/include", 
-            System, false, false, false, Headers);
-
-    // leopard
-    AddPath("/usr/lib/gcc/i686-apple-darwin9/4.0.1/include", System, 
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/powerpc-apple-darwin9/4.0.1/include", 
-            System, false, false, false, Headers);
-    AddPath("/usr/lib/gcc/powerpc-apple-darwin9/"
-            "4.0.1/../../../../powerpc-apple-darwin0/include", 
-            System, false, false, false, Headers);
-
-    // tiger
-    AddPath("/usr/lib/gcc/i686-apple-darwin8/4.0.1/include", System, 
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include", 
-            System, false, false, false, Headers);
-    AddPath("/usr/lib/gcc/powerpc-apple-darwin8/"
-            "4.0.1/../../../../powerpc-apple-darwin8/include", 
-            System, false, false, false, Headers);
-
-    // Ubuntu 7.10 - Gutsy Gibbon
-    AddPath("/usr/lib/gcc/i486-linux-gnu/4.1.3/include", System,
-            false, false, false, Headers);
-
-    // Fedora 8
-    AddPath("/usr/lib/gcc/i386-redhat-linux/4.1.2/include", System,
-            false, false, false, Headers);
-
-    // Fedora 9
-    AddPath("/usr/lib/gcc/i386-redhat-linux/4.3.0/include", System,
-            false, false, false, Headers);
-
-    //Debian testing/lenny x86
-    AddPath("/usr/lib/gcc/i486-linux-gnu/4.2.3/include", System,
-            false, false, false, Headers);
-
-    //Debian testing/lenny amd64
-    AddPath("/usr/lib/gcc/x86_64-linux-gnu/4.2.3/include", System,
-            false, false, false, Headers);
-
-    // Arch Linux 2008-06-24
-    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.3.1/include", System,
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.3.1/include-fixed", System,
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include", System,
-            false, false, false, Headers);
-    AddPath("/usr/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include-fixed",
-            System, false, false, false, Headers);
-
-    // Debian testing/lenny ppc32
-    AddPath("/usr/lib/gcc/powerpc-linux-gnu/4.2.3/include", System,
-            false, false, false, Headers);
-
-    // Gentoo x86 stable
-    AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include", System,
-            false, false, false, Headers);
-
-    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);
-  }
+  if (!nostdinc) 
+    Init.AddDefaultSystemIncludePaths(Lang);
 
   // Now that we have collected all of the include paths, merge them all
   // together and tell the preprocessor about them.
   
-  // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
-  std::vector<DirectoryLookup> SearchList;
-  SearchList = IncludeGroup[Angled];
-  SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
-                    IncludeGroup[System].end());
-  SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
-                    IncludeGroup[After].end());
-  RemoveDuplicates(SearchList);
-  RemoveDuplicates(IncludeGroup[Quoted]);
-  
-  // Prepend QUOTED list on the search list.
-  SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(), 
-                    IncludeGroup[Quoted].end());
-  
-
-  bool DontSearchCurDir = false;  // TODO: set to true if -I- is set?
-  Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
-                         DontSearchCurDir);
-
-  // If verbose, print the list of directories that will be searched.
-  if (Verbose) {
-    fprintf(stderr, "#include \"...\" search starts here:\n");
-    unsigned QuotedIdx = IncludeGroup[Quoted].size();
-    for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
-      if (i == QuotedIdx)
-        fprintf(stderr, "#include <...> search starts here:\n");
-      const char *Name = SearchList[i].getName();
-      const char *Suffix;
-      if (SearchList[i].isNormalDir())
-        Suffix = "";
-      else if (SearchList[i].isFramework())
-        Suffix = " (framework directory)";
-      else {
-        assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
-        Suffix = " (headermap)";
-      }
-      fprintf(stderr, " %s%s\n", Name, Suffix);
-    }
-    fprintf(stderr, "End of search list.\n");
-  }
+  Init.Realize();
 }
 
 //===----------------------------------------------------------------------===//
@@ -1491,11 +1207,6 @@ int main(int argc, char **argv) {
       // Process the -I options and set them in the HeaderInfo.
       HeaderSearch HeaderInfo(FileMgr);
       
-      // FIXME: Sink IncludeGroup into this loop.
-      IncludeGroup[0].clear();
-      IncludeGroup[1].clear();
-      IncludeGroup[2].clear();
-      IncludeGroup[3].clear();
       InitializeIncludePaths(argv[0], HeaderInfo, FileMgr, LangInfo);
       
       // Set up the preprocessor with these options.
diff --git a/include/clang/Driver/InitHeaderSearch.h b/include/clang/Driver/InitHeaderSearch.h
new file mode 100644 (file)
index 0000000..a113456
--- /dev/null
@@ -0,0 +1,74 @@
+//===--- InitHeaderSearch.h - Initialize header search paths ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the InitHeaderSearch class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef DRIVER_INIT_HEADER_SEARCH_H_
+#define DRIVER_INIT_HEADER_SEARCH_H_
+
+#include <string>
+#include <vector>
+
+#include "clang/Lex/DirectoryLookup.h"
+
+namespace clang {
+
+class HeaderSearch;
+class LangOptions;
+
+/// InitHeaderSearch - This class makes it easier to set the search paths of
+///  a HeaderSearch object. InitHeaderSearch stores several search path lists
+///  internally, which can be sent to a HeaderSearch object in one swoop.
+class InitHeaderSearch {
+  std::vector<DirectoryLookup> IncludeGroup[4];
+  HeaderSearch& Headers;
+  bool Verbose;
+  std::string isysroot;
+
+public:
+  /// InitHeaderSearch::IncludeDirGroup - Identifies the several search path
+  ///  lists stored internally.
+  enum IncludeDirGroup {
+    Quoted = 0,     //< `#include ""` paths. Thing `gcc -iquote`.
+    Angled,         //< Paths for both `#include ""` and `#include <>`. (`-I`)
+    System,         //< Like Angled, but marks system directories.
+    After           //< Like System, but searched after the system directories.
+  };
+
+  InitHeaderSearch(HeaderSearch &HS,
+      bool verbose = false, const std::string &iSysroot = "")
+    : Headers(HS), Verbose(verbose), isysroot(iSysroot) {}
+
+  /// AddPath - Add the specified path to the specified group list.
+  void AddPath(const std::string &Path, IncludeDirGroup Group,
+               bool isCXXAware, bool isUserSupplied,
+               bool isFramework);
+
+  /// AddEnvVarPaths - Add a list of paths from an environment variable to a
+  ///  header search list.
+  void AddEnvVarPaths(const char *Name);
+
+  /// AddDefaultEnvVarPaths - Adds list of paths from default environment
+  ///  variables such as CPATH.
+  void AddDefaultEnvVarPaths(const LangOptions &Lang);
+
+  /// AddDefaultSystemIncludePaths - Adds the default system include paths so
+  ///  that e.g. stdio.h is found.
+  void AddDefaultSystemIncludePaths(const LangOptions &Lang);
+
+  /// Realise - Merges all search path lists into one list and send it to
+  /// HeaderSearch.
+  void Realize();
+};
+
+} // end namespace clang
+
+#endif
diff --git a/lib/Driver/InitHeaderSearch.cpp b/lib/Driver/InitHeaderSearch.cpp
new file mode 100644 (file)
index 0000000..7fd36f8
--- /dev/null
@@ -0,0 +1,312 @@
+//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the InitHeaderSearch class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Driver/InitHeaderSearch.h"
+
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/System/Path.h"
+
+#include <vector>
+
+using namespace clang;
+
+void InitHeaderSearch::AddPath(const std::string &Path, IncludeDirGroup Group,
+                               bool isCXXAware, bool isUserSupplied,
+                               bool isFramework) {
+  assert(!Path.empty() && "can't handle empty path here");
+  FileManager &FM = Headers.getFileMgr();
+  
+  // Compute the actual path, taking into consideration -isysroot.
+  llvm::SmallString<256> MappedPath;
+  
+  // Handle isysroot.
+  if (Group == System) {
+    // FIXME: Portability.  This should be a sys::Path interface, this doesn't
+    // handle things like C:\ right, nor win32 \\network\device\blah.
+    if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
+      MappedPath.append(isysroot.begin(), isysroot.end());
+  }
+  
+  MappedPath.append(Path.begin(), Path.end());
+
+  // Compute the DirectoryLookup type.
+  DirectoryLookup::DirType Type;
+  if (Group == Quoted || Group == Angled)
+    Type = DirectoryLookup::NormalHeaderDir;
+  else if (isCXXAware)
+    Type = DirectoryLookup::SystemHeaderDir;
+  else
+    Type = DirectoryLookup::ExternCSystemHeaderDir;
+  
+  
+  // If the directory exists, add it.
+  if (const DirectoryEntry *DE = FM.getDirectory(&MappedPath[0], 
+                                                 &MappedPath[0]+
+                                                 MappedPath.size())) {
+    IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
+                                                  isFramework));
+    return;
+  }
+  
+  // Check to see if this is an apple-style headermap (which are not allowed to
+  // be frameworks).
+  if (!isFramework) {
+    if (const FileEntry *FE = FM.getFile(&MappedPath[0], 
+                                         &MappedPath[0]+MappedPath.size())) {
+      if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
+        // It is a headermap, add it to the search path.
+        IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
+        return;
+      }
+    }
+  }
+  
+  if (Verbose)
+    fprintf(stderr, "ignoring nonexistent directory \"%s\"\n", Path.c_str());
+}
+
+
+void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
+  const char* at = getenv(Name);
+  if (!at)
+    return;
+
+  const char* delim = strchr(at, llvm::sys::PathSeparator);
+  while (delim != 0) {
+    if (delim-at == 0)
+      AddPath(".", Angled, false, true, false);
+    else
+      AddPath(std::string(at, std::string::size_type(delim-at)), Angled, false,
+            true, false);
+    at = delim + 1;
+    delim = strchr(at, llvm::sys::PathSeparator);
+  }
+  if (*at == 0)
+    AddPath(".", Angled, false, true, false);
+  else
+    AddPath(at, Angled, false, true, false);
+}
+
+
+void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang) {
+  // FIXME: temporary hack: hard-coded paths.
+  // FIXME: get these from the target?
+  if (Lang.CPlusPlus) {
+    AddPath("/usr/include/c++/4.2.1", System, true, false, false);
+    AddPath("/usr/include/c++/4.2.1/i686-apple-darwin10", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.2.1/backward", System, true, false, false);
+
+    AddPath("/usr/include/c++/4.0.0", System, true, false, false);
+    AddPath("/usr/include/c++/4.0.0/i686-apple-darwin8", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.0.0/backward", System, true, false, false);
+
+    // Ubuntu 7.10 - Gutsy Gibbon
+    AddPath("/usr/include/c++/4.1.3", System, true, false, false);
+    AddPath("/usr/include/c++/4.1.3/i486-linux-gnu", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.1.3/backward", System, true, false, false);
+
+    // Fedora 8
+    AddPath("/usr/include/c++/4.1.2", System, true, false, false);
+    AddPath("/usr/include/c++/4.1.2/i386-redhat-linux", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.1.2/backward", System, true, false, false);
+
+    // Fedora 9
+    AddPath("/usr/include/c++/4.3.0", System, true, false, false);
+    AddPath("/usr/include/c++/4.3.0/i386-redhat-linux", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.3.0/backward", System, true, false, false);
+
+    // Arch Linux 2008-06-24
+    AddPath("/usr/include/c++/4.3.1", System, true, false, false);
+    AddPath("/usr/include/c++/4.3.1/i686-pc-linux-gnu", System, true, false,
+        false);
+    AddPath("/usr/include/c++/4.3.1/backward", System, true, false, false);
+    AddPath("/usr/include/c++/4.3.1/x86_64-unknown-linux-gnu", System, true,
+        false, false);
+  }
+
+  AddPath("/usr/local/include", System, false, false, false);
+
+  AddPath("/usr/lib/gcc/i686-apple-darwin10/4.2.1/include", System, 
+      false, false, false);
+  AddPath("/usr/lib/gcc/powerpc-apple-darwin10/4.2.1/include", 
+      System, false, false, false);
+
+  // leopard
+  AddPath("/usr/lib/gcc/i686-apple-darwin9/4.0.1/include", System, 
+      false, false, false);
+  AddPath("/usr/lib/gcc/powerpc-apple-darwin9/4.0.1/include", 
+      System, false, false, false);
+  AddPath("/usr/lib/gcc/powerpc-apple-darwin9/"
+      "4.0.1/../../../../powerpc-apple-darwin0/include", 
+      System, false, false, false);
+
+  // tiger
+  AddPath("/usr/lib/gcc/i686-apple-darwin8/4.0.1/include", System, 
+      false, false, false);
+  AddPath("/usr/lib/gcc/powerpc-apple-darwin8/4.0.1/include", 
+      System, false, false, false);
+  AddPath("/usr/lib/gcc/powerpc-apple-darwin8/"
+      "4.0.1/../../../../powerpc-apple-darwin8/include", 
+      System, false, false, false);
+
+  // Ubuntu 7.10 - Gutsy Gibbon
+  AddPath("/usr/lib/gcc/i486-linux-gnu/4.1.3/include", System,
+      false, false, false);
+
+  // Fedora 8
+  AddPath("/usr/lib/gcc/i386-redhat-linux/4.1.2/include", System,
+      false, false, false);
+
+  // Fedora 9
+  AddPath("/usr/lib/gcc/i386-redhat-linux/4.3.0/include", System,
+      false, false, false);
+
+  //Debian testing/lenny x86
+  AddPath("/usr/lib/gcc/i486-linux-gnu/4.2.3/include", System,
+      false, false, false);
+
+  //Debian testing/lenny amd64
+  AddPath("/usr/lib/gcc/x86_64-linux-gnu/4.2.3/include", System,
+      false, false, false);
+
+  // Arch Linux 2008-06-24
+  AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.3.1/include", System,
+      false, false, false);
+  AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.3.1/include-fixed", System,
+      false, false, false);
+  AddPath("/usr/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include", System,
+      false, false, false);
+  AddPath("/usr/lib/gcc/x86_64-unknown-linux-gnu/4.3.1/include-fixed",
+      System, false, false, false);
+
+  // Debian testing/lenny ppc32
+  AddPath("/usr/lib/gcc/powerpc-linux-gnu/4.2.3/include", System,
+      false, false, false);
+
+  // Gentoo x86 stable
+  AddPath("/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include", System,
+      false, false, false);
+
+  AddPath("/usr/include", System, false, false, false);
+  AddPath("/System/Library/Frameworks", System, true, false, true);
+  AddPath("/Library/Frameworks", System, true, false, true);
+}
+
+void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
+  AddEnvVarPaths("CPATH");
+  if (Lang.CPlusPlus && Lang.ObjC1)
+    AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
+  else if (Lang.CPlusPlus)
+    AddEnvVarPaths("CPLUS_INCLUDE_PATH");
+  else if (Lang.ObjC1)
+    AddEnvVarPaths("OBJC_INCLUDE_PATH");
+  else
+    AddEnvVarPaths("C_INCLUDE_PATH");
+}
+
+
+/// RemoveDuplicates - If there are duplicate directory entries in the specified
+/// search list, remove the later (dead) ones.
+static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
+                             bool Verbose) {
+  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
+  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
+  llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
+  for (unsigned i = 0; i != SearchList.size(); ++i) {
+    if (SearchList[i].isNormalDir()) {
+      // If this isn't the first time we've seen this dir, remove it.
+      if (SeenDirs.insert(SearchList[i].getDir()))
+        continue;
+      
+      if (Verbose)
+        fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
+                SearchList[i].getDir()->getName());
+    } else if (SearchList[i].isFramework()) {
+      // If this isn't the first time we've seen this framework dir, remove it.
+      if (SeenFrameworkDirs.insert(SearchList[i].getFrameworkDir()))
+        continue;
+      
+      if (Verbose)
+        fprintf(stderr, "ignoring duplicate framework \"%s\"\n",
+                SearchList[i].getFrameworkDir()->getName());
+      
+    } else {
+      assert(SearchList[i].isHeaderMap() && "Not a headermap or normal dir?");
+      // If this isn't the first time we've seen this headermap, remove it.
+      if (SeenHeaderMaps.insert(SearchList[i].getHeaderMap()))
+        continue;
+      
+      if (Verbose)
+        fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
+                SearchList[i].getDir()->getName());
+    }
+    
+    // This is reached if the current entry is a duplicate.
+    SearchList.erase(SearchList.begin()+i);
+    --i;
+  }
+}
+
+
+void InitHeaderSearch::Realize() {
+  // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
+  std::vector<DirectoryLookup> SearchList;
+  SearchList = IncludeGroup[Angled];
+  SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
+                    IncludeGroup[System].end());
+  SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
+                    IncludeGroup[After].end());
+  RemoveDuplicates(SearchList, Verbose);
+  RemoveDuplicates(IncludeGroup[Quoted], Verbose);
+  
+  // Prepend QUOTED list on the search list.
+  SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(), 
+                    IncludeGroup[Quoted].end());
+  
+
+  bool DontSearchCurDir = false;  // TODO: set to true if -I- is set?
+  Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
+                         DontSearchCurDir);
+
+  // If verbose, print the list of directories that will be searched.
+  if (Verbose) {
+    fprintf(stderr, "#include \"...\" search starts here:\n");
+    unsigned QuotedIdx = IncludeGroup[Quoted].size();
+    for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
+      if (i == QuotedIdx)
+        fprintf(stderr, "#include <...> search starts here:\n");
+      const char *Name = SearchList[i].getName();
+      const char *Suffix;
+      if (SearchList[i].isNormalDir())
+        Suffix = "";
+      else if (SearchList[i].isFramework())
+        Suffix = " (framework directory)";
+      else {
+        assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
+        Suffix = " (headermap)";
+      }
+      fprintf(stderr, " %s%s\n", Name, Suffix);
+    }
+    fprintf(stderr, "End of search list.\n");
+  }
+}
+