clang: lib/Lex/InitHeaderSearch.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

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"

26#include

27

28using namespace clang;

30

31namespace {

32

33struct DirectoryLookupInfo {

36 std::optional UserEntryIdx;

37

39 std::optional UserEntryIdx)

40 : Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {}

41};

42

43

44

45

46class InitHeaderSearch {

47 std::vector IncludePath;

48 std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes;

50 bool Verbose;

51 std::string IncludeSysroot;

52 bool HasSysroot;

53

54public:

55 InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot)

56 : Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)),

57 HasSysroot(!(sysroot.empty() || sysroot == "/")) {}

58

59

60

61

63 std::optional UserEntryIdx = std::nullopt);

64

65

66

67

69 bool isFramework,

70 std::optional UserEntryIdx = std::nullopt);

71

72

73 void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) {

74 SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader);

75 }

76

77

78 void AddMinGWCPlusPlusIncludePaths(StringRef Base,

79 StringRef Arch,

80 StringRef Version);

81

82

83 void AddDefaultCIncludePaths(const llvm::Triple &triple,

85

86

87 void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts,

88 const llvm::Triple &triple,

90

91

92

93 bool ShouldAddDefaultIncludePaths(const llvm::Triple &triple);

94

95

96 void AddDefaultIncludePaths(const LangOptions &Lang,

97 const llvm::Triple &triple,

99

100

102};

103

104}

105

107#if defined(_WIN32)

108 return Path.empty() && llvm::sys::path::is_separator(Path[0]);

109#else

110 return llvm::sys::path::is_absolute(Path);

111#endif

112}

113

115 bool isFramework,

116 std::optional UserEntryIdx) {

117

118

119 if (HasSysroot) {

121 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);

123 return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework,

124 UserEntryIdx);

125 }

126 }

127

128 return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx);

129}

130

131bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,

132 bool isFramework,

133 std::optional UserEntryIdx) {

134 assert(Path.isTriviallyEmpty() && "can't handle empty path here");

135

138 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);

139

140

141 if (HasSysroot && (MappedPathStr.starts_with("/usr/include") ||

142 MappedPathStr.starts_with("/usr/local/include"))) {

143 Headers.getDiags().Report(diag::warn_poison_system_directories)

144 << MappedPathStr;

145 }

146

147

153 } else {

155 }

156

157

160 UserEntryIdx);

161 return true;

162 }

163

164

165

166 if (!isFramework) {

169

171 UserEntryIdx);

172 return true;

173 }

174 }

175 }

176

177 if (Verbose)

178 llvm::errs() << "ignoring nonexistent directory \""

179 << MappedPathStr << "\"\n";

180 return false;

181}

182

183void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base,

184 StringRef Arch,

185 StringRef Version) {

186 AddPath(Base + "/" + Arch + "/" + Version + "/include/c++",

188 AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch,

190 AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward",

192}

193

194void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,

196 if (!ShouldAddDefaultIncludePaths(triple))

197 llvm_unreachable("Include management is handled in the driver.");

198

199 llvm::Triple::OSType os = triple.getOS();

200

202 switch (os) {

203 case llvm::Triple::Win32:

204 if (triple.getEnvironment() != llvm::Triple::Cygnus)

205 break;

206 [[fallthrough]];

207 default:

208

209 AddPath("/usr/local/include", System, false);

210 break;

211 }

212 }

213

214

215

217

218

220 llvm::sys::path::append(P, "include");

222 }

223

224

225

227 return;

228

229

230 StringRef CIncludeDirs(C_INCLUDE_DIRS);

231 if (CIncludeDirs != "") {

233 CIncludeDirs.split(dirs, ":");

234 for (StringRef dir : dirs)

236 return;

237 }

238

239 switch (os) {

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);

245 break;

246 case llvm::Triple::GNU:

247 break;

248 }

249 break;

250 default:

251 break;

252 }

253

255}

256

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.");

262

263

264 llvm::Triple::OSType os = triple.getOS();

265 switch (os) {

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:

270

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");

274

275 AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2");

276 break;

277 }

278 break;

279 default:

280 break;

281 }

282}

283

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:

307 return false;

308

309 case llvm::Triple::Win32:

310 if (triple.getEnvironment() != llvm::Triple::Cygnus ||

311 triple.isOSBinFormatMachO())

312 return false;

313 break;

314

315 case llvm::Triple::UnknownOS:

316 if (triple.isWasm() || triple.isAppleMachO())

317 return false;

318 break;

319

320 default:

321 break;

322 }

323

324 return true;

325}

326

327void InitHeaderSearch::AddDefaultIncludePaths(

328 const LangOptions &Lang, const llvm::Triple &triple,

330

331

332

333

334

335 if (!ShouldAddDefaultIncludePaths(triple))

336 return;

337

338

339

340 if (triple.isOSDarwin()) {

342

343 if (triple.isDriverKit()) {

344 AddPath("/System/DriverKit/System/Library/Frameworks", System, true);

345 } else {

346 AddPath("/System/Library/Frameworks", System, true);

347 AddPath("/System/Library/SubFrameworks", System, true);

348 AddPath("/Library/Frameworks", System, true);

349 }

350 }

351 return;

352 }

353

354 if (Lang.CPlusPlus && Lang.AsmPreprocessor &&

357 AddPath("/usr/include/c++/v1", CXXSystem, false);

358 } else {

359 AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts);

360 }

361 }

362

363 AddDefaultCIncludePaths(triple, HSOpts);

364}

365

366

367

368

369static unsigned RemoveDuplicates(std::vector &SearchList,

370 unsigned First, bool Verbose) {

374 unsigned NonSystemRemoved = 0;

375 for (unsigned i = First; i != SearchList.size(); ++i) {

376 unsigned DirToRemove = i;

377

379

381

382 if (SeenDirs.insert(CurEntry.getDir()).second)

383 continue;

385

386 if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second)

387 continue;

388 } else {

389 assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");

390

391 if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second)

392 continue;

393 }

394

395

396

397

398

399

400

401

403

404 unsigned FirstDir;

405 for (FirstDir = First;; ++FirstDir) {

406 assert(FirstDir != i && "Didn't find dupe?");

407

408 const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup;

409

410

412 continue;

413

414 bool isSame;

416 isSame = SearchEntry.getDir() == CurEntry.getDir();

419 else {

420 assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?");

422 }

423

424 if (isSame)

425 break;

426 }

427

428

429

430 if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User)

431 DirToRemove = FirstDir;

432 }

433

434 if (Verbose) {

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";

440 }

441 if (DirToRemove != i)

442 ++NonSystemRemoved;

443

444

445

446 SearchList.erase(SearchList.begin()+DirToRemove);

447 --i;

448 }

449 return NonSystemRemoved;

450}

451

452

453static std::vector

455 std::vector Lookups;

456 Lookups.reserve(Infos.size());

457 llvm::transform(Infos, std::back_inserter(Lookups),

458 [](const DirectoryLookupInfo &Info) { return Info.Lookup; });

459 return Lookups;

460}

461

462

463static llvm::DenseMap<unsigned, unsigned>

465 llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries;

466 for (unsigned I = 0, E = Infos.size(); I < E; ++I) {

467

468 if (Infos[I].UserEntryIdx)

469 LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx});

470 }

471 return LookupsToUserEntries;

472}

473

474void InitHeaderSearch::Realize(const LangOptions &Lang) {

475

476 std::vector SearchList;

477 SearchList.reserve(IncludePath.size());

478

479

480 for (auto &Include : IncludePath)

482 SearchList.push_back(Include);

483

484

486 unsigned NumQuoted = SearchList.size();

487

488 for (auto &Include : IncludePath)

490 SearchList.push_back(Include);

491

493 unsigned NumAngled = SearchList.size();

494

495 for (auto &Include : IncludePath)

498 ( Lang.CPlusPlus &&

502 SearchList.push_back(Include);

503

504 for (auto &Include : IncludePath)

506 SearchList.push_back(Include);

507

508

509

510

511 unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose);

512 NumAngled -= NonSystemRemoved;

513

516

518

519

520 if (Verbose) {

521 llvm::errs() << "#include \"...\" search starts here:\n";

522 for (unsigned i = 0, e = SearchList.size(); i != e; ++i) {

523 if (i == NumQuoted)

524 llvm::errs() << "#include <...> search starts here:\n";

525 StringRef Name = SearchList[i].Lookup.getName();

526 const char *Suffix;

527 if (SearchList[i].Lookup.isNormalDir())

528 Suffix = "";

529 else if (SearchList[i].Lookup.isFramework())

530 Suffix = " (framework directory)";

531 else {

532 assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup");

533 Suffix = " (headermap)";

534 }

535 llvm::errs() << " " << Name << Suffix << "\n";

536 }

537 llvm::errs() << "End of search list.\n";

538 }

539}

540

544 const llvm::Triple &Triple) {

546

547

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);

552 } else {

553 Init.AddPath(E.Path, E.Group, E.IsFramework, i);

554 }

555 }

556

557 Init.AddDefaultIncludePaths(Lang, Triple, HSOpts);

558

562

564

566 llvm::sys::path::append(P, "include");

569 }

570

571 Init.Realize(Lang);

572}

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.