xref: /llvm-project/clang/lib/Lex/InitHeaderSearch.cpp (revision d6bfe10ac9963eb63e141d6c50e9a183c08d35da)
1f77d115cSJan Svoboda //===--- InitHeaderSearch.cpp - Initialize header search paths ------------===//
2f77d115cSJan Svoboda //
3f77d115cSJan Svoboda // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f77d115cSJan Svoboda // See https://llvm.org/LICENSE.txt for license information.
5f77d115cSJan Svoboda // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f77d115cSJan Svoboda //
7f77d115cSJan Svoboda //===----------------------------------------------------------------------===//
8f77d115cSJan Svoboda //
9f77d115cSJan Svoboda // This file implements the InitHeaderSearch class.
10f77d115cSJan Svoboda //
11f77d115cSJan Svoboda //===----------------------------------------------------------------------===//
12f77d115cSJan Svoboda 
13f77d115cSJan Svoboda #include "clang/Basic/FileManager.h"
14f77d115cSJan Svoboda #include "clang/Basic/LangOptions.h"
15f77d115cSJan Svoboda #include "clang/Config/config.h" // C_INCLUDE_DIRS
16f77d115cSJan Svoboda #include "clang/Lex/HeaderMap.h"
17f77d115cSJan Svoboda #include "clang/Lex/HeaderSearch.h"
18f77d115cSJan Svoboda #include "clang/Lex/HeaderSearchOptions.h"
19f77d115cSJan Svoboda #include "llvm/ADT/SmallPtrSet.h"
20f77d115cSJan Svoboda #include "llvm/ADT/StringExtras.h"
21f77d115cSJan Svoboda #include "llvm/ADT/Twine.h"
22f77d115cSJan Svoboda #include "llvm/Support/ErrorHandling.h"
23f77d115cSJan Svoboda #include "llvm/Support/Path.h"
24f77d115cSJan Svoboda #include "llvm/Support/raw_ostream.h"
2562c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
26a1580d7bSKazu Hirata #include <optional>
27f77d115cSJan Svoboda 
28f77d115cSJan Svoboda using namespace clang;
29f77d115cSJan Svoboda using namespace clang::frontend;
30f77d115cSJan Svoboda 
31f77d115cSJan Svoboda namespace {
32f77d115cSJan Svoboda /// Holds information about a single DirectoryLookup object.
33f77d115cSJan Svoboda struct DirectoryLookupInfo {
34f77d115cSJan Svoboda   IncludeDirGroup Group;
35f77d115cSJan Svoboda   DirectoryLookup Lookup;
366ad0788cSKazu Hirata   std::optional<unsigned> UserEntryIdx;
37f77d115cSJan Svoboda 
38f77d115cSJan Svoboda   DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup,
396ad0788cSKazu Hirata                       std::optional<unsigned> UserEntryIdx)
40f77d115cSJan Svoboda       : Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
41f77d115cSJan Svoboda };
42f77d115cSJan Svoboda 
43ba7a1d9eSMatt Jacobson /// This class makes it easier to set the search paths of a HeaderSearch object.
44ba7a1d9eSMatt Jacobson /// InitHeaderSearch stores several search path lists internally, which can be
45ba7a1d9eSMatt Jacobson /// sent to a HeaderSearch object in one swoop.
46f77d115cSJan Svoboda class InitHeaderSearch {
47f77d115cSJan Svoboda   std::vector<DirectoryLookupInfo> IncludePath;
48f77d115cSJan Svoboda   std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;
49f77d115cSJan Svoboda   HeaderSearch &Headers;
50f77d115cSJan Svoboda   bool Verbose;
51f77d115cSJan Svoboda   std::string IncludeSysroot;
52f77d115cSJan Svoboda   bool HasSysroot;
53f77d115cSJan Svoboda 
54f77d115cSJan Svoboda public:
55f77d115cSJan Svoboda   InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot)
56f77d115cSJan Svoboda       : Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)),
57f77d115cSJan Svoboda         HasSysroot(!(sysroot.empty() || sysroot == "/")) {}
58f77d115cSJan Svoboda 
59ba7a1d9eSMatt Jacobson   /// Add the specified path to the specified group list, prefixing the sysroot
60ba7a1d9eSMatt Jacobson   /// if used.
61f77d115cSJan Svoboda   /// Returns true if the path exists, false if it was ignored.
62f77d115cSJan Svoboda   bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework,
636ad0788cSKazu Hirata                std::optional<unsigned> UserEntryIdx = std::nullopt);
64f77d115cSJan Svoboda 
65ba7a1d9eSMatt Jacobson   /// Add the specified path to the specified group list, without performing any
66ba7a1d9eSMatt Jacobson   /// sysroot remapping.
67f77d115cSJan Svoboda   /// Returns true if the path exists, false if it was ignored.
68f77d115cSJan Svoboda   bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
69f77d115cSJan Svoboda                        bool isFramework,
706ad0788cSKazu Hirata                        std::optional<unsigned> UserEntryIdx = std::nullopt);
71f77d115cSJan Svoboda 
72ba7a1d9eSMatt Jacobson   /// Add the specified prefix to the system header prefix list.
73f77d115cSJan Svoboda   void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {
74f77d115cSJan Svoboda     SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);
75f77d115cSJan Svoboda   }
76f77d115cSJan Svoboda 
77ba7a1d9eSMatt Jacobson   /// Add the necessary paths to support a MinGW libstdc++.
78f77d115cSJan Svoboda   void AddMinGWCPlusPlusIncludePaths(StringRef Base,
79f77d115cSJan Svoboda                                      StringRef Arch,
80f77d115cSJan Svoboda                                      StringRef Version);
81f77d115cSJan Svoboda 
82ba7a1d9eSMatt Jacobson   /// Add paths that should always be searched.
83f77d115cSJan Svoboda   void AddDefaultCIncludePaths(const llvm::Triple &triple,
84f77d115cSJan Svoboda                                const HeaderSearchOptions &HSOpts);
85f77d115cSJan Svoboda 
86ba7a1d9eSMatt Jacobson   /// Add paths that should be searched when compiling c++.
87f77d115cSJan Svoboda   void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts,
88f77d115cSJan Svoboda                                        const llvm::Triple &triple,
89f77d115cSJan Svoboda                                        const HeaderSearchOptions &HSOpts);
90f77d115cSJan Svoboda 
91ba7a1d9eSMatt Jacobson   /// Returns true iff AddDefaultIncludePaths should do anything.  If this
92ba7a1d9eSMatt Jacobson   /// returns false, include paths should instead be handled in the driver.
93ba7a1d9eSMatt Jacobson   bool ShouldAddDefaultIncludePaths(const llvm::Triple &triple);
94ba7a1d9eSMatt Jacobson 
95ba7a1d9eSMatt Jacobson   /// Adds the default system include paths so that e.g. stdio.h is found.
96f77d115cSJan Svoboda   void AddDefaultIncludePaths(const LangOptions &Lang,
97f77d115cSJan Svoboda                               const llvm::Triple &triple,
98f77d115cSJan Svoboda                               const HeaderSearchOptions &HSOpts);
99f77d115cSJan Svoboda 
100ba7a1d9eSMatt Jacobson   /// Merges all search path lists into one list and send it to HeaderSearch.
101f77d115cSJan Svoboda   void Realize(const LangOptions &Lang);
102f77d115cSJan Svoboda };
103f77d115cSJan Svoboda 
104f77d115cSJan Svoboda }  // end anonymous namespace.
105f77d115cSJan Svoboda 
106f77d115cSJan Svoboda static bool CanPrefixSysroot(StringRef Path) {
107f77d115cSJan Svoboda #if defined(_WIN32)
108f77d115cSJan Svoboda   return !Path.empty() && llvm::sys::path::is_separator(Path[0]);
109f77d115cSJan Svoboda #else
110f77d115cSJan Svoboda   return llvm::sys::path::is_absolute(Path);
111f77d115cSJan Svoboda #endif
112f77d115cSJan Svoboda }
113f77d115cSJan Svoboda 
114f77d115cSJan Svoboda bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,
115f77d115cSJan Svoboda                                bool isFramework,
1166ad0788cSKazu Hirata                                std::optional<unsigned> UserEntryIdx) {
117f77d115cSJan Svoboda   // Add the path with sysroot prepended, if desired and this is a system header
118f77d115cSJan Svoboda   // group.
119f77d115cSJan Svoboda   if (HasSysroot) {
120f77d115cSJan Svoboda     SmallString<256> MappedPathStorage;
121f77d115cSJan Svoboda     StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
122f77d115cSJan Svoboda     if (CanPrefixSysroot(MappedPathStr)) {
123f77d115cSJan Svoboda       return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework,
124f77d115cSJan Svoboda                              UserEntryIdx);
125f77d115cSJan Svoboda     }
126f77d115cSJan Svoboda   }
127f77d115cSJan Svoboda 
128f77d115cSJan Svoboda   return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx);
129f77d115cSJan Svoboda }
130f77d115cSJan Svoboda 
131f77d115cSJan Svoboda bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,
132f77d115cSJan Svoboda                                        bool isFramework,
1336ad0788cSKazu Hirata                                        std::optional<unsigned> UserEntryIdx) {
134f77d115cSJan Svoboda   assert(!Path.isTriviallyEmpty() && "can't handle empty path here");
135f77d115cSJan Svoboda 
136f77d115cSJan Svoboda   FileManager &FM = Headers.getFileMgr();
137f77d115cSJan Svoboda   SmallString<256> MappedPathStorage;
138f77d115cSJan Svoboda   StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
139f77d115cSJan Svoboda 
140f77d115cSJan Svoboda   // If use system headers while cross-compiling, emit the warning.
141f3dcc235SKazu Hirata   if (HasSysroot && (MappedPathStr.starts_with("/usr/include") ||
142f3dcc235SKazu Hirata                      MappedPathStr.starts_with("/usr/local/include"))) {
143f77d115cSJan Svoboda     Headers.getDiags().Report(diag::warn_poison_system_directories)
144f77d115cSJan Svoboda         << MappedPathStr;
145f77d115cSJan Svoboda   }
146f77d115cSJan Svoboda 
147f77d115cSJan Svoboda   // Compute the DirectoryLookup type.
148f77d115cSJan Svoboda   SrcMgr::CharacteristicKind Type;
14919b4f17dSJan Svoboda   if (Group == Quoted || Group == Angled) {
150f77d115cSJan Svoboda     Type = SrcMgr::C_User;
151f77d115cSJan Svoboda   } else if (Group == ExternCSystem) {
152f77d115cSJan Svoboda     Type = SrcMgr::C_ExternCSystem;
153f77d115cSJan Svoboda   } else {
154f77d115cSJan Svoboda     Type = SrcMgr::C_System;
155f77d115cSJan Svoboda   }
156f77d115cSJan Svoboda 
157f77d115cSJan Svoboda   // If the directory exists, add it.
158f77d115cSJan Svoboda   if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) {
159f77d115cSJan Svoboda     IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework),
160f77d115cSJan Svoboda                              UserEntryIdx);
161f77d115cSJan Svoboda     return true;
162f77d115cSJan Svoboda   }
163f77d115cSJan Svoboda 
164f77d115cSJan Svoboda   // Check to see if this is an apple-style headermap (which are not allowed to
165f77d115cSJan Svoboda   // be frameworks).
166f77d115cSJan Svoboda   if (!isFramework) {
16789bacc0bSJan Svoboda     if (auto FE = FM.getOptionalFileRef(MappedPathStr)) {
168f77d115cSJan Svoboda       if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) {
169f77d115cSJan Svoboda         // It is a headermap, add it to the search path.
17019b4f17dSJan Svoboda         IncludePath.emplace_back(Group, DirectoryLookup(HM, Type),
171f77d115cSJan Svoboda                                  UserEntryIdx);
172f77d115cSJan Svoboda         return true;
173f77d115cSJan Svoboda       }
174f77d115cSJan Svoboda     }
175f77d115cSJan Svoboda   }
176f77d115cSJan Svoboda 
177f77d115cSJan Svoboda   if (Verbose)
178f77d115cSJan Svoboda     llvm::errs() << "ignoring nonexistent directory \""
179f77d115cSJan Svoboda                  << MappedPathStr << "\"\n";
180f77d115cSJan Svoboda   return false;
181f77d115cSJan Svoboda }
182f77d115cSJan Svoboda 
183f77d115cSJan Svoboda void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,
184f77d115cSJan Svoboda                                                      StringRef Arch,
185f77d115cSJan Svoboda                                                      StringRef Version) {
186f77d115cSJan Svoboda   AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",
187f77d115cSJan Svoboda           CXXSystem, false);
188f77d115cSJan Svoboda   AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,
189f77d115cSJan Svoboda           CXXSystem, false);
190f77d115cSJan Svoboda   AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",
191f77d115cSJan Svoboda           CXXSystem, false);
192f77d115cSJan Svoboda }
193f77d115cSJan Svoboda 
194f77d115cSJan Svoboda void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
195f77d115cSJan Svoboda                                             const HeaderSearchOptions &HSOpts) {
196ba7a1d9eSMatt Jacobson   if (!ShouldAddDefaultIncludePaths(triple))
197f77d115cSJan Svoboda     llvm_unreachable("Include management is handled in the driver.");
198ba7a1d9eSMatt Jacobson 
199ba7a1d9eSMatt Jacobson   llvm::Triple::OSType os = triple.getOS();
200f77d115cSJan Svoboda 
201f77d115cSJan Svoboda   if (HSOpts.UseStandardSystemIncludes) {
202f77d115cSJan Svoboda     switch (os) {
203f77d115cSJan Svoboda     case llvm::Triple::Win32:
204f77d115cSJan Svoboda       if (triple.getEnvironment() != llvm::Triple::Cygnus)
205f77d115cSJan Svoboda         break;
2063f18f7c0SFangrui Song       [[fallthrough]];
207f77d115cSJan Svoboda     default:
208f77d115cSJan Svoboda       // FIXME: temporary hack: hard-coded paths.
209f77d115cSJan Svoboda       AddPath("/usr/local/include", System, false);
210f77d115cSJan Svoboda       break;
211f77d115cSJan Svoboda     }
212f77d115cSJan Svoboda   }
213f77d115cSJan Svoboda 
214f77d115cSJan Svoboda   // Builtin includes use #include_next directives and should be positioned
215f77d115cSJan Svoboda   // just prior C include dirs.
216f77d115cSJan Svoboda   if (HSOpts.UseBuiltinIncludes) {
217f77d115cSJan Svoboda     // Ignore the sys root, we *always* look for clang headers relative to
218f77d115cSJan Svoboda     // supplied path.
219f77d115cSJan Svoboda     SmallString<128> P = StringRef(HSOpts.ResourceDir);
220f77d115cSJan Svoboda     llvm::sys::path::append(P, "include");
221f77d115cSJan Svoboda     AddUnmappedPath(P, ExternCSystem, false);
222f77d115cSJan Svoboda   }
223f77d115cSJan Svoboda 
224f77d115cSJan Svoboda   // All remaining additions are for system include directories, early exit if
225f77d115cSJan Svoboda   // we aren't using them.
226f77d115cSJan Svoboda   if (!HSOpts.UseStandardSystemIncludes)
227f77d115cSJan Svoboda     return;
228f77d115cSJan Svoboda 
229f77d115cSJan Svoboda   // Add dirs specified via 'configure --with-c-include-dirs'.
230f77d115cSJan Svoboda   StringRef CIncludeDirs(C_INCLUDE_DIRS);
231f77d115cSJan Svoboda   if (CIncludeDirs != "") {
232f77d115cSJan Svoboda     SmallVector<StringRef, 5> dirs;
233f77d115cSJan Svoboda     CIncludeDirs.split(dirs, ":");
234f77d115cSJan Svoboda     for (StringRef dir : dirs)
235f77d115cSJan Svoboda       AddPath(dir, ExternCSystem, false);
236f77d115cSJan Svoboda     return;
237f77d115cSJan Svoboda   }
238f77d115cSJan Svoboda 
239f77d115cSJan Svoboda   switch (os) {
240f77d115cSJan Svoboda   case llvm::Triple::Win32:
241f77d115cSJan Svoboda     switch (triple.getEnvironment()) {
242f77d115cSJan Svoboda     default: llvm_unreachable("Include management is handled in the driver.");
243f77d115cSJan Svoboda     case llvm::Triple::Cygnus:
244f77d115cSJan Svoboda       AddPath("/usr/include/w32api", System, false);
245f77d115cSJan Svoboda       break;
246f77d115cSJan Svoboda     case llvm::Triple::GNU:
247f77d115cSJan Svoboda       break;
248f77d115cSJan Svoboda     }
249f77d115cSJan Svoboda     break;
250f77d115cSJan Svoboda   default:
251f77d115cSJan Svoboda     break;
252f77d115cSJan Svoboda   }
253f77d115cSJan Svoboda 
254f77d115cSJan Svoboda   AddPath("/usr/include", ExternCSystem, false);
255f77d115cSJan Svoboda }
256f77d115cSJan Svoboda 
257f77d115cSJan Svoboda void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
258f77d115cSJan Svoboda     const LangOptions &LangOpts, const llvm::Triple &triple,
259f77d115cSJan Svoboda     const HeaderSearchOptions &HSOpts) {
260ba7a1d9eSMatt Jacobson   if (!ShouldAddDefaultIncludePaths(triple))
261ba7a1d9eSMatt Jacobson     llvm_unreachable("Include management is handled in the driver.");
262ba7a1d9eSMatt Jacobson 
263f77d115cSJan Svoboda   // FIXME: temporary hack: hard-coded paths.
264ba7a1d9eSMatt Jacobson   llvm::Triple::OSType os = triple.getOS();
265f77d115cSJan Svoboda   switch (os) {
266f77d115cSJan Svoboda   case llvm::Triple::Win32:
267f77d115cSJan Svoboda     switch (triple.getEnvironment()) {
268f77d115cSJan Svoboda     default: llvm_unreachable("Include management is handled in the driver.");
269f77d115cSJan Svoboda     case llvm::Triple::Cygnus:
270f77d115cSJan Svoboda       // Cygwin-1.7
271f77d115cSJan Svoboda       AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3");
272f77d115cSJan Svoboda       AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3");
273f77d115cSJan Svoboda       AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4");
274f77d115cSJan Svoboda       // g++-4 / Cygwin-1.5
275f77d115cSJan Svoboda       AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");
276f77d115cSJan Svoboda       break;
277f77d115cSJan Svoboda     }
278f77d115cSJan Svoboda     break;
279f77d115cSJan Svoboda   default:
280f77d115cSJan Svoboda     break;
281f77d115cSJan Svoboda   }
282f77d115cSJan Svoboda }
283f77d115cSJan Svoboda 
284ba7a1d9eSMatt Jacobson bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
285ba7a1d9eSMatt Jacobson     const llvm::Triple &triple) {
286f77d115cSJan Svoboda   switch (triple.getOS()) {
287ba7a1d9eSMatt Jacobson   case llvm::Triple::AIX:
288f3476332SBrad Smith   case llvm::Triple::DragonFly:
289d267990eSBrad Smith   case llvm::Triple::ELFIAMCU:
290f77d115cSJan Svoboda   case llvm::Triple::Emscripten:
291ba7a1d9eSMatt Jacobson   case llvm::Triple::FreeBSD:
292196ff0c7SBrad Smith   case llvm::Triple::Fuchsia:
293196ff0c7SBrad Smith   case llvm::Triple::Haiku:
294196ff0c7SBrad Smith   case llvm::Triple::Hurd:
295196ff0c7SBrad Smith   case llvm::Triple::Linux:
296196ff0c7SBrad Smith   case llvm::Triple::LiteOS:
297e4cb6925SBrad Smith   case llvm::Triple::NaCl:
298e449e1dfSBrad Smith   case llvm::Triple::NetBSD:
299e449e1dfSBrad Smith   case llvm::Triple::OpenBSD:
300ecb3cd09SPaul Robinson   case llvm::Triple::PS4:
301ecb3cd09SPaul Robinson   case llvm::Triple::PS5:
302d267990eSBrad Smith   case llvm::Triple::RTEMS:
303f77d115cSJan Svoboda   case llvm::Triple::Solaris:
304dce2245bSPrabhuk   case llvm::Triple::UEFI:
305f77d115cSJan Svoboda   case llvm::Triple::WASI:
306196ff0c7SBrad Smith   case llvm::Triple::ZOS:
307ba7a1d9eSMatt Jacobson     return false;
308f77d115cSJan Svoboda 
309f77d115cSJan Svoboda   case llvm::Triple::Win32:
310f77d115cSJan Svoboda     if (triple.getEnvironment() != llvm::Triple::Cygnus ||
311f77d115cSJan Svoboda         triple.isOSBinFormatMachO())
312ba7a1d9eSMatt Jacobson       return false;
313f77d115cSJan Svoboda     break;
314f77d115cSJan Svoboda 
315f77d115cSJan Svoboda   case llvm::Triple::UnknownOS:
316*d6bfe10aSIan Anderson     if (triple.isWasm() || triple.isAppleMachO())
317ba7a1d9eSMatt Jacobson       return false;
318ba7a1d9eSMatt Jacobson     break;
319ba7a1d9eSMatt Jacobson 
320ba7a1d9eSMatt Jacobson   default:
321f77d115cSJan Svoboda     break;
322f77d115cSJan Svoboda   }
323f77d115cSJan Svoboda 
324ba7a1d9eSMatt Jacobson   return true; // Everything else uses AddDefaultIncludePaths().
325ba7a1d9eSMatt Jacobson }
326ba7a1d9eSMatt Jacobson 
327ba7a1d9eSMatt Jacobson void InitHeaderSearch::AddDefaultIncludePaths(
328ba7a1d9eSMatt Jacobson     const LangOptions &Lang, const llvm::Triple &triple,
329ba7a1d9eSMatt Jacobson     const HeaderSearchOptions &HSOpts) {
330ba7a1d9eSMatt Jacobson   // NB: This code path is going away. All of the logic is moving into the
331ba7a1d9eSMatt Jacobson   // driver which has the information necessary to do target-specific
332ba7a1d9eSMatt Jacobson   // selections of default include paths. Each target which moves there will be
333ba7a1d9eSMatt Jacobson   // exempted from this logic in ShouldAddDefaultIncludePaths() until we can
334ba7a1d9eSMatt Jacobson   // delete the entire pile of code.
335ba7a1d9eSMatt Jacobson   if (!ShouldAddDefaultIncludePaths(triple))
336ba7a1d9eSMatt Jacobson     return;
337ba7a1d9eSMatt Jacobson 
338d34901f3SArthur Eubanks   // NOTE: some additional header search logic is handled in the driver for
339d34901f3SArthur Eubanks   // Darwin.
340d34901f3SArthur Eubanks   if (triple.isOSDarwin()) {
341d34901f3SArthur Eubanks     if (HSOpts.UseStandardSystemIncludes) {
342d34901f3SArthur Eubanks       // Add the default framework include paths on Darwin.
343d34901f3SArthur Eubanks       if (triple.isDriverKit()) {
344d34901f3SArthur Eubanks         AddPath("/System/DriverKit/System/Library/Frameworks", System, true);
345d34901f3SArthur Eubanks       } else {
346d34901f3SArthur Eubanks         AddPath("/System/Library/Frameworks", System, true);
3472d48489cSCyndy Ishida         AddPath("/System/Library/SubFrameworks", System, true);
348d34901f3SArthur Eubanks         AddPath("/Library/Frameworks", System, true);
349d34901f3SArthur Eubanks       }
350d34901f3SArthur Eubanks     }
351d34901f3SArthur Eubanks     return;
352d34901f3SArthur Eubanks   }
353d34901f3SArthur Eubanks 
354f77d115cSJan Svoboda   if (Lang.CPlusPlus && !Lang.AsmPreprocessor &&
355f77d115cSJan Svoboda       HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) {
356f77d115cSJan Svoboda     if (HSOpts.UseLibcxx) {
357f77d115cSJan Svoboda       AddPath("/usr/include/c++/v1", CXXSystem, false);
358f77d115cSJan Svoboda     } else {
359f77d115cSJan Svoboda       AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts);
360f77d115cSJan Svoboda     }
361f77d115cSJan Svoboda   }
362f77d115cSJan Svoboda 
363f77d115cSJan Svoboda   AddDefaultCIncludePaths(triple, HSOpts);
364f77d115cSJan Svoboda }
365f77d115cSJan Svoboda 
366ba7a1d9eSMatt Jacobson /// If there are duplicate directory entries in the specified search list,
367ba7a1d9eSMatt Jacobson /// remove the later (dead) ones.  Returns the number of non-system headers
368ba7a1d9eSMatt Jacobson /// removed, which is used to update NumAngled.
369f77d115cSJan Svoboda static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList,
370f77d115cSJan Svoboda                                  unsigned First, bool Verbose) {
371f77d115cSJan Svoboda   llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs;
372f77d115cSJan Svoboda   llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs;
373f77d115cSJan Svoboda   llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps;
374f77d115cSJan Svoboda   unsigned NonSystemRemoved = 0;
375f77d115cSJan Svoboda   for (unsigned i = First; i != SearchList.size(); ++i) {
376f77d115cSJan Svoboda     unsigned DirToRemove = i;
377f77d115cSJan Svoboda 
378f77d115cSJan Svoboda     const DirectoryLookup &CurEntry = SearchList[i].Lookup;
379f77d115cSJan Svoboda 
380f77d115cSJan Svoboda     if (CurEntry.isNormalDir()) {
381f77d115cSJan Svoboda       // If this isn't the first time we've seen this dir, remove it.
382f77d115cSJan Svoboda       if (SeenDirs.insert(CurEntry.getDir()).second)
383f77d115cSJan Svoboda         continue;
384f77d115cSJan Svoboda     } else if (CurEntry.isFramework()) {
385f77d115cSJan Svoboda       // If this isn't the first time we've seen this framework dir, remove it.
386f77d115cSJan Svoboda       if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second)
387f77d115cSJan Svoboda         continue;
388f77d115cSJan Svoboda     } else {
389f77d115cSJan Svoboda       assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
390f77d115cSJan Svoboda       // If this isn't the first time we've seen this headermap, remove it.
391f77d115cSJan Svoboda       if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second)
392f77d115cSJan Svoboda         continue;
393f77d115cSJan Svoboda     }
394f77d115cSJan Svoboda 
395f77d115cSJan Svoboda     // If we have a normal #include dir/framework/headermap that is shadowed
396f77d115cSJan Svoboda     // later in the chain by a system include location, we actually want to
397f77d115cSJan Svoboda     // ignore the user's request and drop the user dir... keeping the system
398f77d115cSJan Svoboda     // dir.  This is weird, but required to emulate GCC's search path correctly.
399f77d115cSJan Svoboda     //
400f77d115cSJan Svoboda     // Since dupes of system dirs are rare, just rescan to find the original
401f77d115cSJan Svoboda     // that we're nuking instead of using a DenseMap.
402f77d115cSJan Svoboda     if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) {
403f77d115cSJan Svoboda       // Find the dir that this is the same of.
404f77d115cSJan Svoboda       unsigned FirstDir;
405f77d115cSJan Svoboda       for (FirstDir = First;; ++FirstDir) {
406f77d115cSJan Svoboda         assert(FirstDir != i && "Didn't find dupe?");
407f77d115cSJan Svoboda 
408f77d115cSJan Svoboda         const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup;
409f77d115cSJan Svoboda 
410f77d115cSJan Svoboda         // If these are different lookup types, then they can't be the dupe.
411f77d115cSJan Svoboda         if (SearchEntry.getLookupType() != CurEntry.getLookupType())
412f77d115cSJan Svoboda           continue;
413f77d115cSJan Svoboda 
414f77d115cSJan Svoboda         bool isSame;
415f77d115cSJan Svoboda         if (CurEntry.isNormalDir())
416f77d115cSJan Svoboda           isSame = SearchEntry.getDir() == CurEntry.getDir();
417f77d115cSJan Svoboda         else if (CurEntry.isFramework())
418f77d115cSJan Svoboda           isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir();
419f77d115cSJan Svoboda         else {
420f77d115cSJan Svoboda           assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");
421f77d115cSJan Svoboda           isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap();
422f77d115cSJan Svoboda         }
423f77d115cSJan Svoboda 
424f77d115cSJan Svoboda         if (isSame)
425f77d115cSJan Svoboda           break;
426f77d115cSJan Svoboda       }
427f77d115cSJan Svoboda 
428f77d115cSJan Svoboda       // If the first dir in the search path is a non-system dir, zap it
429f77d115cSJan Svoboda       // instead of the system one.
430f77d115cSJan Svoboda       if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User)
431f77d115cSJan Svoboda         DirToRemove = FirstDir;
432f77d115cSJan Svoboda     }
433f77d115cSJan Svoboda 
434f77d115cSJan Svoboda     if (Verbose) {
435f77d115cSJan Svoboda       llvm::errs() << "ignoring duplicate directory \""
436f77d115cSJan Svoboda                    << CurEntry.getName() << "\"\n";
437f77d115cSJan Svoboda       if (DirToRemove != i)
438f77d115cSJan Svoboda         llvm::errs() << "  as it is a non-system directory that duplicates "
439f77d115cSJan Svoboda                      << "a system directory\n";
440f77d115cSJan Svoboda     }
441f77d115cSJan Svoboda     if (DirToRemove != i)
442f77d115cSJan Svoboda       ++NonSystemRemoved;
443f77d115cSJan Svoboda 
444f77d115cSJan Svoboda     // This is reached if the current entry is a duplicate.  Remove the
445f77d115cSJan Svoboda     // DirToRemove (usually the current dir).
446f77d115cSJan Svoboda     SearchList.erase(SearchList.begin()+DirToRemove);
447f77d115cSJan Svoboda     --i;
448f77d115cSJan Svoboda   }
449f77d115cSJan Svoboda   return NonSystemRemoved;
450f77d115cSJan Svoboda }
451f77d115cSJan Svoboda 
452f77d115cSJan Svoboda /// Extract DirectoryLookups from DirectoryLookupInfos.
453f77d115cSJan Svoboda static std::vector<DirectoryLookup>
454f77d115cSJan Svoboda extractLookups(const std::vector<DirectoryLookupInfo> &Infos) {
455f77d115cSJan Svoboda   std::vector<DirectoryLookup> Lookups;
456f77d115cSJan Svoboda   Lookups.reserve(Infos.size());
457f77d115cSJan Svoboda   llvm::transform(Infos, std::back_inserter(Lookups),
458f77d115cSJan Svoboda                   [](const DirectoryLookupInfo &Info) { return Info.Lookup; });
459f77d115cSJan Svoboda   return Lookups;
460f77d115cSJan Svoboda }
461f77d115cSJan Svoboda 
462f77d115cSJan Svoboda /// Collect the mapping between indices of DirectoryLookups and UserEntries.
463f77d115cSJan Svoboda static llvm::DenseMap<unsigned, unsigned>
464f77d115cSJan Svoboda mapToUserEntries(const std::vector<DirectoryLookupInfo> &Infos) {
465f77d115cSJan Svoboda   llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries;
466f77d115cSJan Svoboda   for (unsigned I = 0, E = Infos.size(); I < E; ++I) {
467f77d115cSJan Svoboda     // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry.
468f77d115cSJan Svoboda     if (Infos[I].UserEntryIdx)
469f77d115cSJan Svoboda       LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx});
470f77d115cSJan Svoboda   }
471f77d115cSJan Svoboda   return LookupsToUserEntries;
472f77d115cSJan Svoboda }
473f77d115cSJan Svoboda 
474f77d115cSJan Svoboda void InitHeaderSearch::Realize(const LangOptions &Lang) {
475f77d115cSJan Svoboda   // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList.
476f77d115cSJan Svoboda   std::vector<DirectoryLookupInfo> SearchList;
477f77d115cSJan Svoboda   SearchList.reserve(IncludePath.size());
478f77d115cSJan Svoboda 
479f77d115cSJan Svoboda   // Quoted arguments go first.
480f77d115cSJan Svoboda   for (auto &Include : IncludePath)
481f77d115cSJan Svoboda     if (Include.Group == Quoted)
482f77d115cSJan Svoboda       SearchList.push_back(Include);
483f77d115cSJan Svoboda 
484f77d115cSJan Svoboda   // Deduplicate and remember index.
485f77d115cSJan Svoboda   RemoveDuplicates(SearchList, 0, Verbose);
486f77d115cSJan Svoboda   unsigned NumQuoted = SearchList.size();
487f77d115cSJan Svoboda 
488f77d115cSJan Svoboda   for (auto &Include : IncludePath)
48919b4f17dSJan Svoboda     if (Include.Group == Angled)
490f77d115cSJan Svoboda       SearchList.push_back(Include);
491f77d115cSJan Svoboda 
492f77d115cSJan Svoboda   RemoveDuplicates(SearchList, NumQuoted, Verbose);
493f77d115cSJan Svoboda   unsigned NumAngled = SearchList.size();
494f77d115cSJan Svoboda 
495f77d115cSJan Svoboda   for (auto &Include : IncludePath)
496f77d115cSJan Svoboda     if (Include.Group == System || Include.Group == ExternCSystem ||
497f77d115cSJan Svoboda         (!Lang.ObjC && !Lang.CPlusPlus && Include.Group == CSystem) ||
498f77d115cSJan Svoboda         (/*FIXME !Lang.ObjC && */ Lang.CPlusPlus &&
499f77d115cSJan Svoboda          Include.Group == CXXSystem) ||
500f77d115cSJan Svoboda         (Lang.ObjC && !Lang.CPlusPlus && Include.Group == ObjCSystem) ||
501f77d115cSJan Svoboda         (Lang.ObjC && Lang.CPlusPlus && Include.Group == ObjCXXSystem))
502f77d115cSJan Svoboda       SearchList.push_back(Include);
503f77d115cSJan Svoboda 
504f77d115cSJan Svoboda   for (auto &Include : IncludePath)
505f77d115cSJan Svoboda     if (Include.Group == After)
506f77d115cSJan Svoboda       SearchList.push_back(Include);
507f77d115cSJan Svoboda 
508f77d115cSJan Svoboda   // Remove duplicates across both the Angled and System directories.  GCC does
509f77d115cSJan Svoboda   // this and failing to remove duplicates across these two groups breaks
510f77d115cSJan Svoboda   // #include_next.
511f77d115cSJan Svoboda   unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose);
512f77d115cSJan Svoboda   NumAngled -= NonSystemRemoved;
513f77d115cSJan Svoboda 
514f77d115cSJan Svoboda   Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled,
5153293c088SAaron Ballman                          mapToUserEntries(SearchList));
516f77d115cSJan Svoboda 
517f77d115cSJan Svoboda   Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes);
518f77d115cSJan Svoboda 
519f77d115cSJan Svoboda   // If verbose, print the list of directories that will be searched.
520f77d115cSJan Svoboda   if (Verbose) {
521f77d115cSJan Svoboda     llvm::errs() << "#include \"...\" search starts here:\n";
522f77d115cSJan Svoboda     for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {
523f77d115cSJan Svoboda       if (i == NumQuoted)
524f77d115cSJan Svoboda         llvm::errs() << "#include <...> search starts here:\n";
525f77d115cSJan Svoboda       StringRef Name = SearchList[i].Lookup.getName();
526f77d115cSJan Svoboda       const char *Suffix;
527f77d115cSJan Svoboda       if (SearchList[i].Lookup.isNormalDir())
528f77d115cSJan Svoboda         Suffix = "";
529f77d115cSJan Svoboda       else if (SearchList[i].Lookup.isFramework())
530f77d115cSJan Svoboda         Suffix = " (framework directory)";
531f77d115cSJan Svoboda       else {
532f77d115cSJan Svoboda         assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup");
533f77d115cSJan Svoboda         Suffix = " (headermap)";
534f77d115cSJan Svoboda       }
535f77d115cSJan Svoboda       llvm::errs() << " " << Name << Suffix << "\n";
536f77d115cSJan Svoboda     }
537f77d115cSJan Svoboda     llvm::errs() << "End of search list.\n";
538f77d115cSJan Svoboda   }
539f77d115cSJan Svoboda }
540f77d115cSJan Svoboda 
541f77d115cSJan Svoboda void clang::ApplyHeaderSearchOptions(HeaderSearch &HS,
542f77d115cSJan Svoboda                                      const HeaderSearchOptions &HSOpts,
543f77d115cSJan Svoboda                                      const LangOptions &Lang,
544f77d115cSJan Svoboda                                      const llvm::Triple &Triple) {
545f77d115cSJan Svoboda   InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot);
546f77d115cSJan Svoboda 
547f77d115cSJan Svoboda   // Add the user defined entries.
548f77d115cSJan Svoboda   for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {
549f77d115cSJan Svoboda     const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i];
550f77d115cSJan Svoboda     if (E.IgnoreSysRoot) {
551f77d115cSJan Svoboda       Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework, i);
552f77d115cSJan Svoboda     } else {
553f77d115cSJan Svoboda       Init.AddPath(E.Path, E.Group, E.IsFramework, i);
554f77d115cSJan Svoboda     }
555f77d115cSJan Svoboda   }
556f77d115cSJan Svoboda 
557f77d115cSJan Svoboda   Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
558f77d115cSJan Svoboda 
559f77d115cSJan Svoboda   for (unsigned i = 0, e = HSOpts.SystemHeaderPrefixes.size(); i != e; ++i)
560f77d115cSJan Svoboda     Init.AddSystemHeaderPrefix(HSOpts.SystemHeaderPrefixes[i].Prefix,
561f77d115cSJan Svoboda                                HSOpts.SystemHeaderPrefixes[i].IsSystemHeader);
562f77d115cSJan Svoboda 
563f77d115cSJan Svoboda   if (HSOpts.UseBuiltinIncludes) {
564f77d115cSJan Svoboda     // Set up the builtin include directory in the module map.
565f77d115cSJan Svoboda     SmallString<128> P = StringRef(HSOpts.ResourceDir);
566f77d115cSJan Svoboda     llvm::sys::path::append(P, "include");
5676587d9d8SJan Svoboda     if (auto Dir = HS.getFileMgr().getOptionalDirectoryRef(P))
568f77d115cSJan Svoboda       HS.getModuleMap().setBuiltinIncludeDir(*Dir);
569f77d115cSJan Svoboda   }
570f77d115cSJan Svoboda 
571f77d115cSJan Svoboda   Init.Realize(Lang);
572f77d115cSJan Svoboda }
573