16#include "clang/Config/config.h"
20#include "llvm/ADT/SmallPtrSet.h"
21#include "llvm/ADT/SmallString.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/ADT/StringExtras.h"
24#include "llvm/ADT/Triple.h"
25#include "llvm/ADT/Twine.h"
26#include "llvm/Support/ErrorHandling.h"
27#include "llvm/Support/Path.h"
28#include "llvm/Support/raw_ostream.h"
36struct DirectoryLookupInfo {
39 std::optional<unsigned> UserEntryIdx;
42 std::optional<unsigned> UserEntryIdx)
43 :
Group(
Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
49class InitHeaderSearch {
50 std::vector<DirectoryLookupInfo> IncludePath;
51 std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;
54 std::string IncludeSysroot;
58 InitHeaderSearch(
HeaderSearch &HS,
bool verbose, StringRef sysroot)
59 : Headers(HS), Verbose(verbose), IncludeSysroot(
std::string(sysroot)),
60 HasSysroot(!(sysroot.empty() || sysroot ==
"/")) {}
65 bool AddPath(
const Twine &Path,
IncludeDirGroup Group,
bool isFramework,
66 std::optional<unsigned> UserEntryIdx = std::nullopt);
73 std::optional<unsigned> UserEntryIdx = std::nullopt);
76 void AddSystemHeaderPrefix(StringRef Prefix,
bool IsSystemHeader) {
77 SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);
82 bool AddGnuCPlusPlusIncludePaths(StringRef
Base, StringRef ArchDir,
83 StringRef Dir32, StringRef Dir64,
84 const llvm::Triple &triple);
87 void AddMinGWCPlusPlusIncludePaths(StringRef
Base,
92 void AddDefaultCIncludePaths(
const llvm::Triple &triple,
96 void AddDefaultCPlusPlusIncludePaths(
const LangOptions &LangOpts,
97 const llvm::Triple &triple,
102 bool ShouldAddDefaultIncludePaths(
const llvm::Triple &triple);
105 void AddDefaultIncludePaths(
const LangOptions &Lang,
106 const llvm::Triple &triple,
117 return !Path.empty() && llvm::sys::path::is_separator(Path[0]);
119 return llvm::sys::path::is_absolute(Path);
123bool InitHeaderSearch::AddPath(
const Twine &Path,
IncludeDirGroup Group,
125 std::optional<unsigned> UserEntryIdx) {
130 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
132 return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework,
137 return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx);
140bool InitHeaderSearch::AddUnmappedPath(
const Twine &Path,
IncludeDirGroup Group,
142 std::optional<unsigned> UserEntryIdx) {
143 assert(!Path.isTriviallyEmpty() &&
"can't handle empty path here");
147 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);
150 if (HasSysroot && (MappedPathStr.startswith(
"/usr/include") ||
151 MappedPathStr.startswith(
"/usr/local/include"))) {
176 if (
auto FE = FM.
getFile(MappedPathStr)) {
179 IncludePath.emplace_back(
188 llvm::errs() <<
"ignoring nonexistent directory \""
189 << MappedPathStr <<
"\"\n";
193bool InitHeaderSearch::AddGnuCPlusPlusIncludePaths(StringRef
Base,
197 const llvm::Triple &triple) {
202 llvm::Triple::ArchType
arch = triple.getArch();
203 bool is64bit =
arch == llvm::Triple::ppc64 ||
arch == llvm::Triple::x86_64;
205 AddPath(
Base +
"/" + ArchDir +
"/" + Dir64,
CXXSystem,
false);
207 AddPath(
Base +
"/" + ArchDir +
"/" + Dir32,
CXXSystem,
false);
214void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef
Base,
217 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++",
219 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++/" + Arch,
221 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++/backward",
225void InitHeaderSearch::AddDefaultCIncludePaths(
const llvm::Triple &triple,
227 if (!ShouldAddDefaultIncludePaths(triple))
228 llvm_unreachable(
"Include management is handled in the driver.");
230 llvm::Triple::OSType os = triple.getOS();
234 case llvm::Triple::CloudABI:
235 case llvm::Triple::NaCl:
236 case llvm::Triple::ELFIAMCU:
238 case llvm::Triple::Win32:
239 if (triple.getEnvironment() != llvm::Triple::Cygnus)
244 AddPath(
"/usr/local/include",
System,
false);
255 llvm::sys::path::append(
P,
"include");
265 StringRef CIncludeDirs(C_INCLUDE_DIRS);
266 if (CIncludeDirs !=
"") {
268 CIncludeDirs.split(dirs,
":");
269 for (StringRef dir : dirs)
275 case llvm::Triple::CloudABI: {
278 llvm::sys::path::append(
P,
"../../..", triple.str(),
"include");
283 case llvm::Triple::Haiku:
284 AddPath(
"/boot/system/non-packaged/develop/headers",
System,
false);
285 AddPath(
"/boot/system/develop/headers/os",
System,
false);
286 AddPath(
"/boot/system/develop/headers/os/app",
System,
false);
287 AddPath(
"/boot/system/develop/headers/os/arch",
System,
false);
288 AddPath(
"/boot/system/develop/headers/os/device",
System,
false);
289 AddPath(
"/boot/system/develop/headers/os/drivers",
System,
false);
290 AddPath(
"/boot/system/develop/headers/os/game",
System,
false);
291 AddPath(
"/boot/system/develop/headers/os/interface",
System,
false);
292 AddPath(
"/boot/system/develop/headers/os/kernel",
System,
false);
293 AddPath(
"/boot/system/develop/headers/os/locale",
System,
false);
294 AddPath(
"/boot/system/develop/headers/os/mail",
System,
false);
295 AddPath(
"/boot/system/develop/headers/os/media",
System,
false);
296 AddPath(
"/boot/system/develop/headers/os/midi",
System,
false);
297 AddPath(
"/boot/system/develop/headers/os/midi2",
System,
false);
298 AddPath(
"/boot/system/develop/headers/os/net",
System,
false);
299 AddPath(
"/boot/system/develop/headers/os/opengl",
System,
false);
300 AddPath(
"/boot/system/develop/headers/os/storage",
System,
false);
301 AddPath(
"/boot/system/develop/headers/os/support",
System,
false);
302 AddPath(
"/boot/system/develop/headers/os/translation",
System,
false);
303 AddPath(
"/boot/system/develop/headers/os/add-ons/graphics",
System,
false);
304 AddPath(
"/boot/system/develop/headers/os/add-ons/input_server",
System,
false);
305 AddPath(
"/boot/system/develop/headers/os/add-ons/mail_daemon",
System,
false);
306 AddPath(
"/boot/system/develop/headers/os/add-ons/registrar",
System,
false);
307 AddPath(
"/boot/system/develop/headers/os/add-ons/screen_saver",
System,
false);
308 AddPath(
"/boot/system/develop/headers/os/add-ons/tracker",
System,
false);
309 AddPath(
"/boot/system/develop/headers/os/be_apps/Deskbar",
System,
false);
310 AddPath(
"/boot/system/develop/headers/os/be_apps/NetPositive",
System,
false);
311 AddPath(
"/boot/system/develop/headers/os/be_apps/Tracker",
System,
false);
312 AddPath(
"/boot/system/develop/headers/3rdparty",
System,
false);
313 AddPath(
"/boot/system/develop/headers/bsd",
System,
false);
314 AddPath(
"/boot/system/develop/headers/glibc",
System,
false);
315 AddPath(
"/boot/system/develop/headers/posix",
System,
false);
316 AddPath(
"/boot/system/develop/headers",
System,
false);
318 case llvm::Triple::RTEMS:
320 case llvm::Triple::Win32:
321 switch (triple.getEnvironment()) {
322 default: llvm_unreachable(
"Include management is handled in the driver.");
323 case llvm::Triple::Cygnus:
324 AddPath(
"/usr/include/w32api",
System,
false);
326 case llvm::Triple::GNU:
335 case llvm::Triple::CloudABI:
336 case llvm::Triple::RTEMS:
337 case llvm::Triple::NaCl:
338 case llvm::Triple::ELFIAMCU:
346void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
347 const LangOptions &LangOpts,
const llvm::Triple &triple,
349 if (!ShouldAddDefaultIncludePaths(triple))
350 llvm_unreachable(
"Include management is handled in the driver.");
353 llvm::Triple::OSType os = triple.getOS();
355 case llvm::Triple::Win32:
356 switch (triple.getEnvironment()) {
357 default: llvm_unreachable(
"Include management is handled in the driver.");
358 case llvm::Triple::Cygnus:
360 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.7.3");
361 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.5.3");
362 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.3.4");
364 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.3.2");
368 case llvm::Triple::DragonFly:
369 AddPath(
"/usr/include/c++/5.0",
CXXSystem,
false);
371 case llvm::Triple::Minix:
372 AddGnuCPlusPlusIncludePaths(
"/usr/gnu/include/c++/4.4.3",
380bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
381 const llvm::Triple &triple) {
382 switch (triple.getOS()) {
383 case llvm::Triple::AIX:
384 case llvm::Triple::Emscripten:
385 case llvm::Triple::FreeBSD:
386 case llvm::Triple::NetBSD:
387 case llvm::Triple::OpenBSD:
388 case llvm::Triple::PS4:
389 case llvm::Triple::PS5:
390 case llvm::Triple::Fuchsia:
391 case llvm::Triple::Hurd:
392 case llvm::Triple::Linux:
393 case llvm::Triple::Solaris:
394 case llvm::Triple::WASI:
397 case llvm::Triple::Win32:
398 if (triple.getEnvironment() != llvm::Triple::Cygnus ||
399 triple.isOSBinFormatMachO())
403 case llvm::Triple::UnknownOS:
415void InitHeaderSearch::AddDefaultIncludePaths(
416 const LangOptions &Lang,
const llvm::Triple &triple,
423 if (!ShouldAddDefaultIncludePaths(triple))
428 if (triple.isOSDarwin()) {
431 if (triple.isDriverKit()) {
432 AddPath(
"/System/DriverKit/System/Library/Frameworks",
System,
true);
434 AddPath(
"/System/Library/Frameworks",
System,
true);
435 AddPath(
"/Library/Frameworks",
System,
true);
441 if (
Lang.CPlusPlus && !
Lang.AsmPreprocessor &&
444 AddPath(
"/usr/include/c++/v1",
CXXSystem,
false);
446 AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts);
450 AddDefaultCIncludePaths(triple, HSOpts);
457 unsigned First,
bool Verbose) {
461 unsigned NonSystemRemoved = 0;
462 for (
unsigned i =
First; i != SearchList.size(); ++i) {
463 unsigned DirToRemove = i;
469 if (SeenDirs.insert(CurEntry.
getDir()).second)
476 assert(CurEntry.
isHeaderMap() &&
"Not a headermap or normal dir?");
478 if (SeenHeaderMaps.insert(CurEntry.
getHeaderMap()).second)
492 for (FirstDir =
First;; ++FirstDir) {
493 assert(FirstDir != i &&
"Didn't find dupe?");
507 assert(CurEntry.
isHeaderMap() &&
"Not a headermap or normal dir?");
517 if (SearchList[FirstDir].Lookup.getDirCharacteristic() ==
SrcMgr::C_User)
518 DirToRemove = FirstDir;
522 llvm::errs() <<
"ignoring duplicate directory \""
523 << CurEntry.
getName() <<
"\"\n";
524 if (DirToRemove != i)
525 llvm::errs() <<
" as it is a non-system directory that duplicates "
526 <<
"a system directory\n";
528 if (DirToRemove != i)
533 SearchList.erase(SearchList.begin()+DirToRemove);
536 return NonSystemRemoved;
540static std::vector<DirectoryLookup>
542 std::vector<DirectoryLookup> Lookups;
543 Lookups.reserve(Infos.size());
544 llvm::transform(Infos, std::back_inserter(Lookups),
545 [](
const DirectoryLookupInfo &Info) {
return Info.Lookup; });
550static llvm::DenseMap<unsigned, unsigned>
552 llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries;
553 for (
unsigned I = 0, E = Infos.size(); I < E; ++I) {
555 if (Infos[I].UserEntryIdx)
556 LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx});
558 return LookupsToUserEntries;
561void InitHeaderSearch::Realize(
const LangOptions &Lang) {
563 std::vector<DirectoryLookupInfo> SearchList;
564 SearchList.reserve(IncludePath.size());
567 for (
auto &Include : IncludePath)
569 SearchList.push_back(Include);
573 unsigned NumQuoted = SearchList.size();
575 for (
auto &Include : IncludePath)
577 SearchList.push_back(Include);
580 unsigned NumAngled = SearchList.size();
582 for (
auto &Include : IncludePath)
589 SearchList.push_back(Include);
591 for (
auto &Include : IncludePath)
593 SearchList.push_back(Include);
598 unsigned NonSystemRemoved =
RemoveDuplicates(SearchList, NumQuoted, Verbose);
599 NumAngled -= NonSystemRemoved;
601 bool DontSearchCurDir =
false;
609 llvm::errs() <<
"#include \"...\" search starts here:\n";
610 for (
unsigned i = 0, e = SearchList.size(); i != e; ++i) {
612 llvm::errs() <<
"#include <...> search starts here:\n";
613 StringRef Name = SearchList[i].Lookup.getName();
615 if (SearchList[i].Lookup.isNormalDir())
617 else if (SearchList[i].Lookup.isFramework())
618 Suffix =
" (framework directory)";
620 assert(SearchList[i].Lookup.isHeaderMap() &&
"Unknown DirectoryLookup");
621 Suffix =
" (headermap)";
623 llvm::errs() <<
" " << Name << Suffix <<
"\n";
625 llvm::errs() <<
"End of search list.\n";
632 const llvm::Triple &Triple) {
636 for (
unsigned i = 0, e = HSOpts.
UserEntries.size(); i != e; ++i) {
645 Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
654 llvm::sys::path::append(
P,
"include");
Defines the clang::FileManager interface and associated types.
Defines the clang::LangOptions interface.
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
DirectoryLookup - This class represents one entry in the search list that specifies the search order ...
SrcMgr::CharacteristicKind getDirCharacteristic() const
DirCharacteristic - The type of directory this is, one of the DirType enum values.
const DirectoryEntry * getFrameworkDir() const
getFrameworkDir - Return the directory that this framework refers to.
bool isFramework() const
isFramework - True if this is a framework directory.
bool isHeaderMap() const
isHeaderMap - Return true if this is a header map, not a normal directory.
StringRef getName() const
getName - Return the directory or filename corresponding to this lookup object.
LookupType_t getLookupType() const
getLookupType - Return the kind of directory lookup that this is: either a normal directory,...
const DirectoryEntry * getDir() const
getDir - Return the directory that this entry refers to.
bool isNormalDir() const
isNormalDir - Return true if this is a normal directory, not a header map.
const HeaderMap * getHeaderMap() const
getHeaderMap - Return the directory that this entry refers to.
Implements support for file system lookup, file system caching, and directory search management.
llvm::ErrorOr< const DirectoryEntry * > getDirectory(StringRef DirName, bool CacheFailure=true)
Lookup, cache, and verify the specified directory (real or virtual).
llvm::ErrorOr< const FileEntry * > getFile(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Lookup, cache, and verify the specified file (real or virtual).
OptionalDirectoryEntryRef getOptionalDirectoryRef(StringRef DirName, bool CacheFailure=true)
Get a DirectoryEntryRef if it exists, without doing anything on error.
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
void setBuiltinIncludeDir(const DirectoryEntry *Dir)
Set the directory that contains Clang-supplied include files, such as our stdarg.h or tgmath....
The base class of the type hierarchy.
CharacteristicKind
Indicates whether a file or directory holds normal user code, system code, or system code which is im...
IncludeDirGroup
IncludeDirGroup - Identifies the group an include Entry belongs to, representing its relative positiv...
@ CXXSystem
Like System, but only used for C++.
@ Angled
Paths for '#include <>' added by '-I'.
@ CSystem
Like System, but only used for C.
@ System
Like Angled, but marks system directories.
@ Quoted
'#include ""' paths, added by 'gcc -iquote'.
@ ExternCSystem
Like System, but headers are implicitly wrapped in extern "C".
@ ObjCSystem
Like System, but only used for ObjC.
@ IndexHeaderMap
Like Angled, but marks header maps used when building frameworks.
@ ObjCXXSystem
Like System, but only used for ObjC++.
@ After
Like System, but searched after the system directories.
void ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, const llvm::Triple &triple)
Apply the header search options to get given HeaderSearch object.