15#include "clang/Config/config.h"
19#include "llvm/ADT/SmallPtrSet.h"
20#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/Twine.h"
22#include "llvm/Support/ErrorHandling.h"
23#include "llvm/Support/Path.h"
24#include "llvm/Support/raw_ostream.h"
25#include "llvm/TargetParser/Triple.h"
33struct DirectoryLookupInfo {
36 std::optional<unsigned> UserEntryIdx;
39 std::optional<unsigned> UserEntryIdx)
40 :
Group(
Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}
46class InitHeaderSearch {
47 std::vector<DirectoryLookupInfo> IncludePath;
48 std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;
51 std::string IncludeSysroot;
55 InitHeaderSearch(
HeaderSearch &HS,
bool verbose, StringRef sysroot)
56 : Headers(HS), Verbose(verbose), IncludeSysroot(
std::string(sysroot)),
57 HasSysroot(!(sysroot.empty() || sysroot ==
"/")) {}
63 std::optional<unsigned> UserEntryIdx = std::nullopt);
70 std::optional<unsigned> UserEntryIdx = std::nullopt);
73 void AddSystemHeaderPrefix(StringRef Prefix,
bool IsSystemHeader) {
74 SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);
78 void AddMinGWCPlusPlusIncludePaths(StringRef
Base,
83 void AddDefaultCIncludePaths(
const llvm::Triple &triple,
87 void AddDefaultCPlusPlusIncludePaths(
const LangOptions &LangOpts,
88 const llvm::Triple &triple,
93 bool ShouldAddDefaultIncludePaths(
const llvm::Triple &triple);
96 void AddDefaultIncludePaths(
const LangOptions &Lang,
97 const llvm::Triple &triple,
108 return !
Path.empty() && llvm::sys::path::is_separator(
Path[0]);
110 return llvm::sys::path::is_absolute(
Path);
116 std::optional<unsigned> UserEntryIdx) {
121 StringRef MappedPathStr =
Path.toStringRef(MappedPathStorage);
123 return AddUnmappedPath(IncludeSysroot +
Path, Group, isFramework,
128 return AddUnmappedPath(
Path, Group, isFramework, UserEntryIdx);
133 std::optional<unsigned> UserEntryIdx) {
134 assert(!
Path.isTriviallyEmpty() &&
"can't handle empty path here");
138 StringRef MappedPathStr =
Path.toStringRef(MappedPathStorage);
141 if (HasSysroot && (MappedPathStr.starts_with(
"/usr/include") ||
142 MappedPathStr.starts_with(
"/usr/local/include"))) {
178 llvm::errs() <<
"ignoring nonexistent directory \""
179 << MappedPathStr <<
"\"\n";
183void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef
Base,
186 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++",
188 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++/" + Arch,
190 AddPath(
Base +
"/" + Arch +
"/" + Version +
"/include/c++/backward",
194void InitHeaderSearch::AddDefaultCIncludePaths(
const llvm::Triple &triple,
196 if (!ShouldAddDefaultIncludePaths(triple))
197 llvm_unreachable(
"Include management is handled in the driver.");
199 llvm::Triple::OSType os = triple.getOS();
203 case llvm::Triple::Win32:
204 if (triple.getEnvironment() != llvm::Triple::Cygnus)
209 AddPath(
"/usr/local/include",
System,
false);
220 llvm::sys::path::append(
P,
"include");
230 StringRef CIncludeDirs(C_INCLUDE_DIRS);
231 if (CIncludeDirs !=
"") {
233 CIncludeDirs.split(dirs,
":");
234 for (StringRef dir : dirs)
240 case llvm::Triple::Win32:
241 switch (triple.getEnvironment()) {
242 default: llvm_unreachable(
"Include management is handled in the driver.");
243 case llvm::Triple::Cygnus:
244 AddPath(
"/usr/include/w32api",
System,
false);
246 case llvm::Triple::GNU:
257void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths(
258 const LangOptions &LangOpts,
const llvm::Triple &triple,
260 if (!ShouldAddDefaultIncludePaths(triple))
261 llvm_unreachable(
"Include management is handled in the driver.");
264 llvm::Triple::OSType os = triple.getOS();
266 case llvm::Triple::Win32:
267 switch (triple.getEnvironment()) {
268 default: llvm_unreachable(
"Include management is handled in the driver.");
269 case llvm::Triple::Cygnus:
271 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.7.3");
272 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.5.3");
273 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.3.4");
275 AddMinGWCPlusPlusIncludePaths(
"/usr/lib/gcc",
"i686-pc-cygwin",
"4.3.2");
284bool InitHeaderSearch::ShouldAddDefaultIncludePaths(
285 const llvm::Triple &triple) {
286 switch (triple.getOS()) {
287 case llvm::Triple::AIX:
288 case llvm::Triple::DragonFly:
289 case llvm::Triple::ELFIAMCU:
290 case llvm::Triple::Emscripten:
291 case llvm::Triple::FreeBSD:
292 case llvm::Triple::Fuchsia:
293 case llvm::Triple::Haiku:
294 case llvm::Triple::Hurd:
295 case llvm::Triple::Linux:
296 case llvm::Triple::LiteOS:
297 case llvm::Triple::NaCl:
298 case llvm::Triple::NetBSD:
299 case llvm::Triple::OpenBSD:
300 case llvm::Triple::PS4:
301 case llvm::Triple::PS5:
302 case llvm::Triple::RTEMS:
303 case llvm::Triple::Solaris:
304 case llvm::Triple::UEFI:
305 case llvm::Triple::WASI:
306 case llvm::Triple::ZOS:
309 case llvm::Triple::Win32:
310 if (triple.getEnvironment() != llvm::Triple::Cygnus ||
311 triple.isOSBinFormatMachO())
315 case llvm::Triple::UnknownOS:
327void InitHeaderSearch::AddDefaultIncludePaths(
328 const LangOptions &Lang,
const llvm::Triple &triple,
335 if (!ShouldAddDefaultIncludePaths(triple))
340 if (triple.isOSDarwin()) {
343 if (triple.isDriverKit()) {
344 AddPath(
"/System/DriverKit/System/Library/Frameworks",
System,
true);
346 AddPath(
"/System/Library/Frameworks",
System,
true);
347 AddPath(
"/System/Library/SubFrameworks",
System,
true);
348 AddPath(
"/Library/Frameworks",
System,
true);
354 if (
Lang.CPlusPlus && !
Lang.AsmPreprocessor &&
357 AddPath(
"/usr/include/c++/v1",
CXXSystem,
false);
359 AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts);
363 AddDefaultCIncludePaths(triple, HSOpts);
370 unsigned First,
bool Verbose) {
374 unsigned NonSystemRemoved = 0;
375 for (
unsigned i =
First; i != SearchList.size(); ++i) {
376 unsigned DirToRemove = i;
382 if (SeenDirs.insert(CurEntry.
getDir()).second)
389 assert(CurEntry.
isHeaderMap() &&
"Not a headermap or normal dir?");
391 if (SeenHeaderMaps.insert(CurEntry.
getHeaderMap()).second)
405 for (FirstDir =
First;; ++FirstDir) {
406 assert(FirstDir != i &&
"Didn't find dupe?");
420 assert(CurEntry.
isHeaderMap() &&
"Not a headermap or normal dir?");
430 if (SearchList[FirstDir].Lookup.getDirCharacteristic() ==
SrcMgr::C_User)
431 DirToRemove = FirstDir;
435 llvm::errs() <<
"ignoring duplicate directory \""
436 << CurEntry.
getName() <<
"\"\n";
437 if (DirToRemove != i)
438 llvm::errs() <<
" as it is a non-system directory that duplicates "
439 <<
"a system directory\n";
441 if (DirToRemove != i)
446 SearchList.erase(SearchList.begin()+DirToRemove);
449 return NonSystemRemoved;
453static std::vector<DirectoryLookup>
455 std::vector<DirectoryLookup> Lookups;
456 Lookups.reserve(Infos.size());
457 llvm::transform(Infos, std::back_inserter(Lookups),
458 [](
const DirectoryLookupInfo &Info) {
return Info.Lookup; });
463static llvm::DenseMap<unsigned, unsigned>
465 llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries;
466 for (
unsigned I = 0,
E = Infos.size(); I <
E; ++I) {
468 if (Infos[I].UserEntryIdx)
469 LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx});
471 return LookupsToUserEntries;
474void InitHeaderSearch::Realize(
const LangOptions &Lang) {
476 std::vector<DirectoryLookupInfo> SearchList;
477 SearchList.reserve(IncludePath.size());
480 for (
auto &Include : IncludePath)
482 SearchList.push_back(Include);
486 unsigned NumQuoted = SearchList.size();
488 for (
auto &Include : IncludePath)
490 SearchList.push_back(Include);
493 unsigned NumAngled = SearchList.size();
495 for (
auto &Include : IncludePath)
502 SearchList.push_back(Include);
504 for (
auto &Include : IncludePath)
506 SearchList.push_back(Include);
511 unsigned NonSystemRemoved =
RemoveDuplicates(SearchList, NumQuoted, Verbose);
512 NumAngled -= NonSystemRemoved;
521 llvm::errs() <<
"#include \"...\" search starts here:\n";
522 for (
unsigned i = 0, e = SearchList.size(); i != e; ++i) {
524 llvm::errs() <<
"#include <...> search starts here:\n";
525 StringRef Name = SearchList[i].Lookup.getName();
527 if (SearchList[i].Lookup.isNormalDir())
529 else if (SearchList[i].Lookup.isFramework())
530 Suffix =
" (framework directory)";
532 assert(SearchList[i].Lookup.isHeaderMap() &&
"Unknown DirectoryLookup");
533 Suffix =
" (headermap)";
535 llvm::errs() <<
" " << Name << Suffix <<
"\n";
537 llvm::errs() <<
"End of search list.\n";
544 const llvm::Triple &Triple) {
548 for (
unsigned i = 0, e = HSOpts.
UserEntries.size(); i != e; ++i) {
550 if (
E.IgnoreSysRoot) {
551 Init.AddUnmappedPath(
E.Path,
E.Group,
E.IsFramework, i);
553 Init.AddPath(
E.Path,
E.Group,
E.IsFramework, i);
557 Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);
566 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.
OptionalFileEntryRef getOptionalFileRef(StringRef Filename, bool OpenFile=false, bool CacheFailure=true)
Get a FileEntryRef if it exists, without doing anything on error.
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(DirectoryEntryRef 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.
@ ObjCXXSystem
Like System, but only used for ObjC++.
@ After
Like System, but searched after the system directories.
The JSON file list parser is used to communicate input to InstallAPI.
void ApplyHeaderSearchOptions(HeaderSearch &HS, const HeaderSearchOptions &HSOpts, const LangOptions &Lang, const llvm::Triple &triple)
Apply the header search options to get given HeaderSearch object.