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 {

35 DirectoryLookup Lookup;

36 std::optional UserEntryIdx;

37

38 DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup,

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

62 bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework,

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

64

65

66

67

68 bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group,

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 AddDefaultCIncludePaths(const llvm::Triple &triple,

79 const HeaderSearchOptions &HSOpts);

80

81

82

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

84

85

86 void AddDefaultIncludePaths(const LangOptions &Lang,

87 const llvm::Triple &triple,

88 const HeaderSearchOptions &HSOpts);

89

90

91 void Realize(const LangOptions &Lang);

92};

93

94}

95

97#if defined(_WIN32)

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

99#else

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

101#endif

102}

103

104bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group,

105 bool isFramework,

106 std::optional UserEntryIdx) {

107

108

109 if (HasSysroot) {

110 SmallString<256> MappedPathStorage;

111 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);

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

114 UserEntryIdx);

115 }

116 }

117

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

119}

120

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

122 bool isFramework,

123 std::optional UserEntryIdx) {

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

125

126 FileManager &FM = Headers.getFileMgr();

127 SmallString<256> MappedPathStorage;

128 StringRef MappedPathStr = Path.toStringRef(MappedPathStorage);

129

130

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

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

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

134 << MappedPathStr;

135 }

136

137

143 } else {

145 }

146

147

149 IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework),

150 UserEntryIdx);

151 return true;

152 }

153

154

155

156 if (!isFramework) {

158 if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) {

159

160 IncludePath.emplace_back(Group, DirectoryLookup(HM, Type),

161 UserEntryIdx);

162 return true;

163 }

164 }

165 }

166

167 if (Verbose)

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

169 << MappedPathStr << "\"\n";

170 return false;

171}

172

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

174 const HeaderSearchOptions &HSOpts) {

175 if (!ShouldAddDefaultIncludePaths(triple))

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

177

179

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

181 }

182

183

184

186

187

188 SmallString<128> P = StringRef(HSOpts.ResourceDir);

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

191 }

192

193

194

196 return;

197

198

199 StringRef CIncludeDirs(C_INCLUDE_DIRS);

200 if (CIncludeDirs != "") {

201 SmallVector<StringRef, 5> dirs;

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

203 for (StringRef dir : dirs)

205 return;

206 }

207

209}

210

211bool InitHeaderSearch::ShouldAddDefaultIncludePaths(

212 const llvm::Triple &triple) {

213 switch (triple.getOS()) {

214 case llvm::Triple::AIX:

215 case llvm::Triple::DragonFly:

216 case llvm::Triple::ELFIAMCU:

217 case llvm::Triple::Emscripten:

218 case llvm::Triple::FreeBSD:

219 case llvm::Triple::Fuchsia:

220 case llvm::Triple::Haiku:

221 case llvm::Triple::Hurd:

222 case llvm::Triple::Linux:

223 case llvm::Triple::LiteOS:

224 case llvm::Triple::Managarm:

225 case llvm::Triple::NetBSD:

226 case llvm::Triple::OpenBSD:

227 case llvm::Triple::PS4:

228 case llvm::Triple::PS5:

229 case llvm::Triple::RTEMS:

230 case llvm::Triple::Solaris:

231 case llvm::Triple::UEFI:

232 case llvm::Triple::WASI:

233 case llvm::Triple::Win32:

234 case llvm::Triple::ZOS:

235 return false;

236

237 case llvm::Triple::UnknownOS:

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

239 return false;

240 break;

241

242 default:

243 break;

244 }

245

246 if (triple.isOSDarwin())

247 return false;

248

249 return true;

250}

251

252void InitHeaderSearch::AddDefaultIncludePaths(

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

254 const HeaderSearchOptions &HSOpts) {

255

256

257

258

259

260 if (!ShouldAddDefaultIncludePaths(triple))

261 return;

262

263 if (Lang.CPlusPlus && Lang.AsmPreprocessor &&

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

267 }

268 }

269

270 AddDefaultCIncludePaths(triple, HSOpts);

271}

272

273

274

275

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

277 unsigned First, bool Verbose) {

281 unsigned NonSystemRemoved = 0;

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

283 unsigned DirToRemove = i;

284

286

288

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

290 continue;

292

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

294 continue;

295 } else {

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

297

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

299 continue;

300 }

301

302

303

304

305

306

307

308

310

311 unsigned FirstDir;

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

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

314

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

316

317

319 continue;

320

321 bool isSame;

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

326 else {

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

329 }

330

331 if (isSame)

332 break;

333 }

334

335

336

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

338 DirToRemove = FirstDir;

339 }

340

341 if (Verbose) {

342 llvm::errs() << "ignoring duplicate directory \""

343 << CurEntry.getName() << "\"\n";

344 if (DirToRemove != i)

345 llvm::errs() << " as it is a non-system directory that duplicates "

346 << "a system directory\n";

347 }

348 if (DirToRemove != i)

349 ++NonSystemRemoved;

350

351

352

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

354 --i;

355 }

356 return NonSystemRemoved;

357}

358

359

360static std::vector

362 std::vector Lookups;

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

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

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

366 return Lookups;

367}

368

369

370static llvm::DenseMap<unsigned, unsigned>

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

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

374

375 if (Infos[I].UserEntryIdx)

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

377 }

378 return LookupsToUserEntries;

379}

380

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

382

383 std::vector SearchList;

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

385

386

387 for (auto &Include : IncludePath)

389 SearchList.push_back(Include);

390

391

393 unsigned NumQuoted = SearchList.size();

394

395 for (auto &Include : IncludePath)

397 SearchList.push_back(Include);

398

400 unsigned NumAngled = SearchList.size();

401

402 for (auto &Include : IncludePath)

405 ( Lang.CPlusPlus &&

409 SearchList.push_back(Include);

410

411 for (auto &Include : IncludePath)

413 SearchList.push_back(Include);

414

415

416

417

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

419 NumAngled -= NonSystemRemoved;

420

423

425

426

427 if (Verbose) {

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

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

430 if (i == NumQuoted)

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

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

433 const char *Suffix;

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

435 Suffix = "";

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

437 Suffix = " (framework directory)";

438 else {

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

440 Suffix = " (headermap)";

441 }

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

443 }

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

445 }

446}

447

451 const llvm::Triple &Triple) {

453

454

455 for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) {

459 } else {

461 }

462 }

463

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

465

469

471

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

476 }

477

478 Init.Realize(Lang);

479}

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.

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....

CharacteristicKind

Indicates whether a file or directory holds normal user code, system code, or system code which is im...

@ HeaderSearch

Remove unused header search paths including header maps.

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.

Definition InitHeaderSearch.cpp:448

@ Type

The name was classified as a type.