InitHeaderSearch.cpp revision d3f88343af2dec3459493fafa22532317321eaf0
1//===--- InitHeaderSearch.cpp - Initialize header search paths ----------*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the InitHeaderSearch class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Frontend/InitHeaderSearch.h"
15#include "clang/Lex/HeaderSearch.h"
16#include "clang/Basic/FileManager.h"
17#include "clang/Basic/LangOptions.h"
18#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/SmallPtrSet.h"
20#include "llvm/Support/raw_ostream.h"
21#include "llvm/System/Path.h"
22#include "llvm/Config/config.h"
23#include <cstdio>
24#ifdef _MSC_VER
25  #define WIN32_LEAN_AND_MEAN 1
26  #include <windows.h>
27#endif
28using namespace clang;
29
30void InitHeaderSearch::AddPath(const llvm::StringRef &Path,
31                               IncludeDirGroup Group, bool isCXXAware,
32                               bool isUserSupplied, bool isFramework,
33                               bool IgnoreSysRoot) {
34  assert(!Path.empty() && "can't handle empty path here");
35  FileManager &FM = Headers.getFileMgr();
36
37  // Compute the actual path, taking into consideration -isysroot.
38  llvm::SmallString<256> MappedPath;
39
40  // Handle isysroot.
41  if (Group == System && !IgnoreSysRoot) {
42    // FIXME: Portability.  This should be a sys::Path interface, this doesn't
43    // handle things like C:\ right, nor win32 \\network\device\blah.
44    if (isysroot.size() != 1 || isysroot[0] != '/') // Add isysroot if present.
45      MappedPath.append(isysroot.begin(), isysroot.end());
46  }
47
48  MappedPath.append(Path.begin(), Path.end());
49
50  // Compute the DirectoryLookup type.
51  SrcMgr::CharacteristicKind Type;
52  if (Group == Quoted || Group == Angled)
53    Type = SrcMgr::C_User;
54  else if (isCXXAware)
55    Type = SrcMgr::C_System;
56  else
57    Type = SrcMgr::C_ExternCSystem;
58
59
60  // If the directory exists, add it.
61  if (const DirectoryEntry *DE = FM.getDirectory(MappedPath.str())) {
62    IncludeGroup[Group].push_back(DirectoryLookup(DE, Type, isUserSupplied,
63                                                  isFramework));
64    return;
65  }
66
67  // Check to see if this is an apple-style headermap (which are not allowed to
68  // be frameworks).
69  if (!isFramework) {
70    if (const FileEntry *FE = FM.getFile(MappedPath.str())) {
71      if (const HeaderMap *HM = Headers.CreateHeaderMap(FE)) {
72        // It is a headermap, add it to the search path.
73        IncludeGroup[Group].push_back(DirectoryLookup(HM, Type,isUserSupplied));
74        return;
75      }
76    }
77  }
78
79  if (Verbose)
80    llvm::errs() << "ignoring nonexistent directory \""
81                 << MappedPath.str() << "\"\n";
82}
83
84
85void InitHeaderSearch::AddEnvVarPaths(const char *Name) {
86  const char* at = getenv(Name);
87  if (!at || *at == 0) // Empty string should not add '.' path.
88    return;
89
90  const char* delim = strchr(at, llvm::sys::PathSeparator);
91  while (delim != 0) {
92    if (delim-at == 0)
93      AddPath(".", Angled, false, true, false);
94    else
95      AddPath(llvm::StringRef(at, delim-at), Angled, false, true, false);
96    at = delim + 1;
97    delim = strchr(at, llvm::sys::PathSeparator);
98  }
99  if (*at == 0)
100    AddPath(".", Angled, false, true, false);
101  else
102    AddPath(at, Angled, false, true, false);
103}
104
105void InitHeaderSearch::AddGnuCPlusPlusIncludePaths(const std::string &Base,
106                                                  const char *Arch) {
107    AddPath(Base, System, true, false, false);
108    AddPath(Base + "/" + Arch, System, true, false, false);
109    AddPath(Base + "/backward", System, true, false, false);
110}
111
112void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(const std::string &Base,
113                                                     const char *Arch,
114                                                     const char *Version) {
115    std::string localBase = Base + "/" + Arch + "/" + Version + "/include";
116    AddPath(localBase, System, true, false, false);
117    AddPath(localBase + "/c++", System, true, false, false);
118    AddPath(localBase + "/c++/backward", System, true, false, false);
119}
120
121  // FIXME: This probably should goto to some platform utils place.
122#ifdef _MSC_VER
123  // Read registry string.
124bool getSystemRegistryString(const char *keyPath, const char *valueName,
125                       char *value, size_t maxLength) {
126  HKEY hRootKey = NULL;
127  HKEY hKey = NULL;
128  const char* subKey = NULL;
129  DWORD valueType;
130  DWORD valueSize = maxLength - 1;
131  bool returnValue = false;
132  if (strncmp(keyPath, "HKEY_CLASSES_ROOT\\", 18) == 0) {
133    hRootKey = HKEY_CLASSES_ROOT;
134    subKey = keyPath + 18;
135  }
136  else if (strncmp(keyPath, "HKEY_USERS\\", 11) == 0) {
137    hRootKey = HKEY_USERS;
138    subKey = keyPath + 11;
139  }
140  else if (strncmp(keyPath, "HKEY_LOCAL_MACHINE\\", 19) == 0) {
141    hRootKey = HKEY_LOCAL_MACHINE;
142    subKey = keyPath + 19;
143  }
144  else if (strncmp(keyPath, "HKEY_CURRENT_USER\\", 18) == 0) {
145    hRootKey = HKEY_CURRENT_USER;
146    subKey = keyPath + 18;
147  }
148  else
149    return(false);
150  long lResult = RegOpenKeyEx(hRootKey, subKey, 0, KEY_READ, &hKey);
151  if (lResult == ERROR_SUCCESS) {
152    lResult = RegQueryValueEx(hKey, valueName, NULL, &valueType,
153      (LPBYTE)value, &valueSize);
154    if (lResult == ERROR_SUCCESS)
155      returnValue = true;
156    RegCloseKey(hKey);
157  }
158  return(returnValue);
159}
160#else // _MSC_VER
161  // Read registry string.
162bool getSystemRegistryString(const char *, const char *, char *, size_t) {
163  return(false);
164}
165#endif // _MSC_VER
166
167  // Get Visual Studio installation directory.
168bool getVisualStudioDir(std::string &path) {
169  // Try the Windows registry first.
170  char vs80IDEInstallDir[256];
171  char vs90IDEInstallDir[256];
172  const char* vsIDEInstallDir = NULL;
173  bool has80 = getSystemRegistryString(
174    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0",
175    "InstallDir", vs80IDEInstallDir, sizeof(vs80IDEInstallDir) - 1);
176  bool has90 = getSystemRegistryString(
177    "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0",
178    "InstallDir", vs90IDEInstallDir, sizeof(vs90IDEInstallDir) - 1);
179    // If we have both vc80 and vc90, pick version we were compiled with.
180  if (has80 && has90) {
181    #ifdef _MSC_VER
182      #if (_MSC_VER >= 1500)  // VC90
183          vsIDEInstallDir = vs90IDEInstallDir;
184      #elif (_MSC_VER == 1400) // VC80
185          vsIDEInstallDir = vs80IDEInstallDir;
186      #else
187          vsIDEInstallDir = vs90IDEInstallDir;
188      #endif
189    #else
190      vsIDEInstallDir = vs90IDEInstallDir;
191    #endif
192  }
193  else if (has90)
194    vsIDEInstallDir = vs90IDEInstallDir;
195  else if (has80)
196    vsIDEInstallDir = vs80IDEInstallDir;
197  if (vsIDEInstallDir && *vsIDEInstallDir) {
198    char *p = (char*)strstr(vsIDEInstallDir, "\\Common7\\IDE");
199    if (p)
200      *p = '\0';
201    path = vsIDEInstallDir;
202    return(true);
203  }
204  else {
205    // Try the environment.
206    const char* vs90comntools = getenv("VS90COMNTOOLS");
207    const char* vs80comntools = getenv("VS80COMNTOOLS");
208    const char* vscomntools = NULL;
209      // If we have both vc80 and vc90, pick version we were compiled with.
210    if (vs90comntools && vs80comntools) {
211      #if (_MSC_VER >= 1500)  // VC90
212          vscomntools = vs90comntools;
213      #elif (_MSC_VER == 1400) // VC80
214          vscomntools = vs80comntools;
215      #else
216          vscomntools = vs90comntools;
217      #endif
218    }
219    else if (vs90comntools)
220      vscomntools = vs90comntools;
221    else if (vs80comntools)
222      vscomntools = vs80comntools;
223    if (vscomntools && *vscomntools) {
224      char *p = (char*)strstr(vscomntools, "\\Common7\\Tools");
225      if (p)
226        *p = '\0';
227      path = vscomntools;
228      return(true);
229    }
230    else
231      return(false);
232  }
233  return(false);
234}
235
236void InitHeaderSearch::AddDefaultSystemIncludePaths(const LangOptions &Lang,
237                                                   const llvm::Triple &triple) {
238  // FIXME: temporary hack: hard-coded paths.
239  llvm::Triple::OSType os = triple.getOS();
240
241  switch (os) {
242  case llvm::Triple::Win32:
243    {
244      std::string VSDir;
245      if (getVisualStudioDir(VSDir)) {
246        AddPath(VSDir + "\\VC\\include", System, false, false, false);
247        AddPath(VSDir + "\\VC\\PlatformSDK\\Include",
248          System, false, false, false);
249      }
250      else {
251          // Default install paths.
252        AddPath("C:/Program Files/Microsoft Visual Studio 9.0/VC/include",
253          System, false, false, false);
254        AddPath(
255        "C:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
256          System, false, false, false);
257        AddPath("C:/Program Files/Microsoft Visual Studio 8/VC/include",
258          System, false, false, false);
259        AddPath(
260        "C:/Program Files/Microsoft Visual Studio 8/VC/PlatformSDK/Include",
261          System, false, false, false);
262          // For some clang developers.
263        AddPath("G:/Program Files/Microsoft Visual Studio 9.0/VC/include",
264          System, false, false, false);
265        AddPath(
266        "G:/Program Files/Microsoft Visual Studio 9.0/VC/PlatformSDK/Include",
267          System, false, false, false);
268      }
269    }
270    break;
271  case llvm::Triple::Cygwin:
272    if (Lang.CPlusPlus) {
273      AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include",
274        System, false, false, false);
275      AddPath("/lib/gcc/i686-pc-cygwin/3.4.4/include/c++",
276        System, false, false, false);
277    }
278    AddPath("/usr/include", System, false, false, false);
279    break;
280  case llvm::Triple::MinGW64:
281    if (Lang.CPlusPlus) { // I'm guessing here.
282      // Try gcc 4.4.0
283      AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.4.0");
284      // Try gcc 4.3.0
285      AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw64", "4.3.0");
286    }
287    // Fall through.
288  case llvm::Triple::MinGW32:
289    if (Lang.CPlusPlus) {
290      // Try gcc 4.4.0
291      AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.4.0");
292      // Try gcc 4.3.0
293      AddMinGWCPlusPlusIncludePaths("c:/MinGW/lib/gcc", "mingw32", "4.3.0");
294    }
295    AddPath("c:/mingw/include", System, true, false, false);
296    break;
297  default:
298    if (Lang.CPlusPlus) {
299      switch (os) {
300        case llvm::Triple::Darwin:
301          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.2.1",
302                                      "i686-apple-darwin10");
303          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.0.0",
304                                      "i686-apple-darwin8");
305          break;
306        case llvm::Triple::Linux:
307          // Ubuntu 7.10 - Gutsy Gibbon
308          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.3",
309                                      "i486-linux-gnu");
310          // Ubuntu 9.04
311          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.3",
312                                      "x86_64-linux-gnu");
313          // Fedora 8
314          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.1.2",
315                                      "i386-redhat-linux");
316          // Fedora 9
317          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.0",
318                                      "i386-redhat-linux");
319          // Fedora 10
320          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.2",
321                                      "i386-redhat-linux");
322          // openSUSE 11.1
323          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
324                                      "i586-suse-linux");
325          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
326                                      "x86_64-suse-linux");
327          // openSUSE 11.2
328          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
329                                      "i586-suse-linux");
330          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.4",
331                                      "x86_64-suse-linux");
332          // Arch Linux 2008-06-24
333          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
334                                      "i686-pc-linux-gnu");
335          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3.1",
336                                      "x86_64-unknown-linux-gnu");
337          // Gentoo x86 2009.0 stable
338          AddGnuCPlusPlusIncludePaths(
339             "/usr/lib/gcc/i686-pc-linux-gnu/4.3.2/include/g++-v4",
340             "i686-pc-linux-gnu");
341          // Gentoo x86 2008.0 stable
342          AddGnuCPlusPlusIncludePaths(
343             "/usr/lib/gcc/i686-pc-linux-gnu/4.1.2/include/g++-v4",
344             "i686-pc-linux-gnu");
345          // Ubuntu 8.10
346          AddGnuCPlusPlusIncludePaths("/usr/include/c++/4.3",
347                                      "i486-pc-linux-gnu");
348          // Gentoo amd64 stable
349          AddGnuCPlusPlusIncludePaths(
350             "/usr/lib/gcc/x86_64-pc-linux-gnu/4.1.2/include/g++-v4",
351             "i686-pc-linux-gnu");
352          break;
353        case llvm::Triple::FreeBSD:
354          // DragonFly
355          AddPath("/usr/include/c++/4.1", System, true, false, false);
356          // FreeBSD
357          AddPath("/usr/include/c++/4.2", System, true, false, false);
358          break;
359        case llvm::Triple::Solaris:
360          // AuroraUX
361          AddGnuCPlusPlusIncludePaths("/opt/gcc4/include/c++/4.2.4",
362                                      "i386-pc-solaris2.11");
363          break;
364        default:
365          break;
366      }
367    }
368    break;
369  }
370
371  AddPath("/usr/local/include", System, false, false, false);
372  AddPath("/usr/include", System, false, false, false);
373  AddPath("/System/Library/Frameworks", System, true, false, true);
374  AddPath("/Library/Frameworks", System, true, false, true);
375}
376
377void InitHeaderSearch::AddDefaultEnvVarPaths(const LangOptions &Lang) {
378  AddEnvVarPaths("CPATH");
379  if (Lang.CPlusPlus && Lang.ObjC1)
380    AddEnvVarPaths("OBJCPLUS_INCLUDE_PATH");
381  else if (Lang.CPlusPlus)
382    AddEnvVarPaths("CPLUS_INCLUDE_PATH");
383  else if (Lang.ObjC1)
384    AddEnvVarPaths("OBJC_INCLUDE_PATH");
385  else
386    AddEnvVarPaths("C_INCLUDE_PATH");
387}
388
389
390/// RemoveDuplicates - If there are duplicate directory entries in the specified
391/// search list, remove the later (dead) ones.
392static void RemoveDuplicates(std::vector<DirectoryLookup> &SearchList,
393                             bool Verbose) {
394  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
395  llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
396  llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
397  for (unsigned i = 0; i != SearchList.size(); ++i) {
398    unsigned DirToRemove = i;
399
400    const DirectoryLookup &CurEntry = SearchList[i];
401
402    if (CurEntry.isNormalDir()) {
403      // If this isn't the first time we've seen this dir, remove it.
404      if (SeenDirs.insert(CurEntry.getDir()))
405        continue;
406    } else if (CurEntry.isFramework()) {
407      // If this isn't the first time we've seen this framework dir, remove it.
408      if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()))
409        continue;
410    } else {
411      assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
412      // If this isn't the first time we've seen this headermap, remove it.
413      if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()))
414        continue;
415    }
416
417    // If we have a normal #include dir/framework/headermap that is shadowed
418    // later in the chain by a system include location, we actually want to
419    // ignore the user's request and drop the user dir... keeping the system
420    // dir.  This is weird, but required to emulate GCC's search path correctly.
421    //
422    // Since dupes of system dirs are rare, just rescan to find the original
423    // that we're nuking instead of using a DenseMap.
424    if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
425      // Find the dir that this is the same of.
426      unsigned FirstDir;
427      for (FirstDir = 0; ; ++FirstDir) {
428        assert(FirstDir != i && "Didn't find dupe?");
429
430        const DirectoryLookup &SearchEntry = SearchList[FirstDir];
431
432        // If these are different lookup types, then they can't be the dupe.
433        if (SearchEntry.getLookupType() != CurEntry.getLookupType())
434          continue;
435
436        bool isSame;
437        if (CurEntry.isNormalDir())
438          isSame = SearchEntry.getDir() == CurEntry.getDir();
439        else if (CurEntry.isFramework())
440          isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
441        else {
442          assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
443          isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
444        }
445
446        if (isSame)
447          break;
448      }
449
450      // If the first dir in the search path is a non-system dir, zap it
451      // instead of the system one.
452      if (SearchList[FirstDir].getDirCharacteristic() == SrcMgr::C_User)
453        DirToRemove = FirstDir;
454    }
455
456    if (Verbose) {
457      fprintf(stderr, "ignoring duplicate directory \"%s\"\n",
458              CurEntry.getName());
459      if (DirToRemove != i)
460        fprintf(stderr, "  as it is a non-system directory that duplicates"
461                " a system directory\n");
462    }
463
464    // This is reached if the current entry is a duplicate.  Remove the
465    // DirToRemove (usually the current dir).
466    SearchList.erase(SearchList.begin()+DirToRemove);
467    --i;
468  }
469}
470
471
472void InitHeaderSearch::Realize() {
473  // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
474  std::vector<DirectoryLookup> SearchList;
475  SearchList = IncludeGroup[Angled];
476  SearchList.insert(SearchList.end(), IncludeGroup[System].begin(),
477                    IncludeGroup[System].end());
478  SearchList.insert(SearchList.end(), IncludeGroup[After].begin(),
479                    IncludeGroup[After].end());
480  RemoveDuplicates(SearchList, Verbose);
481  RemoveDuplicates(IncludeGroup[Quoted], Verbose);
482
483  // Prepend QUOTED list on the search list.
484  SearchList.insert(SearchList.begin(), IncludeGroup[Quoted].begin(),
485                    IncludeGroup[Quoted].end());
486
487
488  bool DontSearchCurDir = false;  // TODO: set to true if -I- is set?
489  Headers.SetSearchPaths(SearchList, IncludeGroup[Quoted].size(),
490                         DontSearchCurDir);
491
492  // If verbose, print the list of directories that will be searched.
493  if (Verbose) {
494    fprintf(stderr, "#include \"...\" search starts here:\n");
495    unsigned QuotedIdx = IncludeGroup[Quoted].size();
496    for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
497      if (i == QuotedIdx)
498        fprintf(stderr, "#include <...> search starts here:\n");
499      const char *Name = SearchList[i].getName();
500      const char *Suffix;
501      if (SearchList[i].isNormalDir())
502        Suffix = "";
503      else if (SearchList[i].isFramework())
504        Suffix = " (framework directory)";
505      else {
506        assert(SearchList[i].isHeaderMap() && "Unknown DirectoryLookup");
507        Suffix = " (headermap)";
508      }
509      fprintf(stderr, " %s%s\n", Name, Suffix);
510    }
511    fprintf(stderr, "End of search list.\n");
512  }
513}
514