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