104eeddc0SDimitry Andric //===--- InitHeaderSearch.cpp - Initialize header search paths ------------===// 204eeddc0SDimitry Andric // 304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 604eeddc0SDimitry Andric // 704eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 804eeddc0SDimitry Andric // 904eeddc0SDimitry Andric // This file implements the InitHeaderSearch class. 1004eeddc0SDimitry Andric // 1104eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1204eeddc0SDimitry Andric 1304eeddc0SDimitry Andric #include "clang/Basic/DiagnosticFrontend.h" 1404eeddc0SDimitry Andric #include "clang/Basic/FileManager.h" 1504eeddc0SDimitry Andric #include "clang/Basic/LangOptions.h" 1604eeddc0SDimitry Andric #include "clang/Config/config.h" // C_INCLUDE_DIRS 1704eeddc0SDimitry Andric #include "clang/Lex/HeaderMap.h" 1804eeddc0SDimitry Andric #include "clang/Lex/HeaderSearch.h" 1904eeddc0SDimitry Andric #include "clang/Lex/HeaderSearchOptions.h" 2004eeddc0SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 2104eeddc0SDimitry Andric #include "llvm/ADT/SmallString.h" 2204eeddc0SDimitry Andric #include "llvm/ADT/SmallVector.h" 2304eeddc0SDimitry Andric #include "llvm/ADT/StringExtras.h" 2404eeddc0SDimitry Andric #include "llvm/ADT/Twine.h" 2504eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2604eeddc0SDimitry Andric #include "llvm/Support/Path.h" 2704eeddc0SDimitry Andric #include "llvm/Support/raw_ostream.h" 2806c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h" 29bdd1243dSDimitry Andric #include <optional> 3004eeddc0SDimitry Andric 3104eeddc0SDimitry Andric using namespace clang; 3204eeddc0SDimitry Andric using namespace clang::frontend; 3304eeddc0SDimitry Andric 3404eeddc0SDimitry Andric namespace { 3504eeddc0SDimitry Andric /// Holds information about a single DirectoryLookup object. 3604eeddc0SDimitry Andric struct DirectoryLookupInfo { 3704eeddc0SDimitry Andric IncludeDirGroup Group; 3804eeddc0SDimitry Andric DirectoryLookup Lookup; 39bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx; 4004eeddc0SDimitry Andric 4104eeddc0SDimitry Andric DirectoryLookupInfo(IncludeDirGroup Group, DirectoryLookup Lookup, 42bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx) 4304eeddc0SDimitry Andric : Group(Group), Lookup(Lookup), UserEntryIdx(UserEntryIdx) {} 4404eeddc0SDimitry Andric }; 4504eeddc0SDimitry Andric 46bdd1243dSDimitry Andric /// This class makes it easier to set the search paths of a HeaderSearch object. 47bdd1243dSDimitry Andric /// InitHeaderSearch stores several search path lists internally, which can be 48bdd1243dSDimitry Andric /// sent to a HeaderSearch object in one swoop. 4904eeddc0SDimitry Andric class InitHeaderSearch { 5004eeddc0SDimitry Andric std::vector<DirectoryLookupInfo> IncludePath; 5104eeddc0SDimitry Andric std::vector<std::pair<std::string, bool> > SystemHeaderPrefixes; 5204eeddc0SDimitry Andric HeaderSearch &Headers; 5304eeddc0SDimitry Andric bool Verbose; 5404eeddc0SDimitry Andric std::string IncludeSysroot; 5504eeddc0SDimitry Andric bool HasSysroot; 5604eeddc0SDimitry Andric 5704eeddc0SDimitry Andric public: 5804eeddc0SDimitry Andric InitHeaderSearch(HeaderSearch &HS, bool verbose, StringRef sysroot) 5904eeddc0SDimitry Andric : Headers(HS), Verbose(verbose), IncludeSysroot(std::string(sysroot)), 6004eeddc0SDimitry Andric HasSysroot(!(sysroot.empty() || sysroot == "/")) {} 6104eeddc0SDimitry Andric 62bdd1243dSDimitry Andric /// Add the specified path to the specified group list, prefixing the sysroot 63bdd1243dSDimitry Andric /// if used. 6404eeddc0SDimitry Andric /// Returns true if the path exists, false if it was ignored. 6504eeddc0SDimitry Andric bool AddPath(const Twine &Path, IncludeDirGroup Group, bool isFramework, 66bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx = std::nullopt); 6704eeddc0SDimitry Andric 68bdd1243dSDimitry Andric /// Add the specified path to the specified group list, without performing any 69bdd1243dSDimitry Andric /// sysroot remapping. 7004eeddc0SDimitry Andric /// Returns true if the path exists, false if it was ignored. 7104eeddc0SDimitry Andric bool AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, 7204eeddc0SDimitry Andric bool isFramework, 73bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx = std::nullopt); 7404eeddc0SDimitry Andric 75bdd1243dSDimitry Andric /// Add the specified prefix to the system header prefix list. 7604eeddc0SDimitry Andric void AddSystemHeaderPrefix(StringRef Prefix, bool IsSystemHeader) { 7704eeddc0SDimitry Andric SystemHeaderPrefixes.emplace_back(std::string(Prefix), IsSystemHeader); 7804eeddc0SDimitry Andric } 7904eeddc0SDimitry Andric 80bdd1243dSDimitry Andric /// Add the necessary paths to support a MinGW libstdc++. 8104eeddc0SDimitry Andric void AddMinGWCPlusPlusIncludePaths(StringRef Base, 8204eeddc0SDimitry Andric StringRef Arch, 8304eeddc0SDimitry Andric StringRef Version); 8404eeddc0SDimitry Andric 85bdd1243dSDimitry Andric /// Add paths that should always be searched. 8604eeddc0SDimitry Andric void AddDefaultCIncludePaths(const llvm::Triple &triple, 8704eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts); 8804eeddc0SDimitry Andric 89bdd1243dSDimitry Andric /// Add paths that should be searched when compiling c++. 9004eeddc0SDimitry Andric void AddDefaultCPlusPlusIncludePaths(const LangOptions &LangOpts, 9104eeddc0SDimitry Andric const llvm::Triple &triple, 9204eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts); 9304eeddc0SDimitry Andric 94bdd1243dSDimitry Andric /// Returns true iff AddDefaultIncludePaths should do anything. If this 95bdd1243dSDimitry Andric /// returns false, include paths should instead be handled in the driver. 96bdd1243dSDimitry Andric bool ShouldAddDefaultIncludePaths(const llvm::Triple &triple); 97bdd1243dSDimitry Andric 98bdd1243dSDimitry Andric /// Adds the default system include paths so that e.g. stdio.h is found. 9904eeddc0SDimitry Andric void AddDefaultIncludePaths(const LangOptions &Lang, 10004eeddc0SDimitry Andric const llvm::Triple &triple, 10104eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts); 10204eeddc0SDimitry Andric 103bdd1243dSDimitry Andric /// Merges all search path lists into one list and send it to HeaderSearch. 10404eeddc0SDimitry Andric void Realize(const LangOptions &Lang); 10504eeddc0SDimitry Andric }; 10604eeddc0SDimitry Andric 10704eeddc0SDimitry Andric } // end anonymous namespace. 10804eeddc0SDimitry Andric 10904eeddc0SDimitry Andric static bool CanPrefixSysroot(StringRef Path) { 11004eeddc0SDimitry Andric #if defined(_WIN32) 11104eeddc0SDimitry Andric return !Path.empty() && llvm::sys::path::is_separator(Path[0]); 11204eeddc0SDimitry Andric #else 11304eeddc0SDimitry Andric return llvm::sys::path::is_absolute(Path); 11404eeddc0SDimitry Andric #endif 11504eeddc0SDimitry Andric } 11604eeddc0SDimitry Andric 11704eeddc0SDimitry Andric bool InitHeaderSearch::AddPath(const Twine &Path, IncludeDirGroup Group, 11804eeddc0SDimitry Andric bool isFramework, 119bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx) { 12004eeddc0SDimitry Andric // Add the path with sysroot prepended, if desired and this is a system header 12104eeddc0SDimitry Andric // group. 12204eeddc0SDimitry Andric if (HasSysroot) { 12304eeddc0SDimitry Andric SmallString<256> MappedPathStorage; 12404eeddc0SDimitry Andric StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); 12504eeddc0SDimitry Andric if (CanPrefixSysroot(MappedPathStr)) { 12604eeddc0SDimitry Andric return AddUnmappedPath(IncludeSysroot + Path, Group, isFramework, 12704eeddc0SDimitry Andric UserEntryIdx); 12804eeddc0SDimitry Andric } 12904eeddc0SDimitry Andric } 13004eeddc0SDimitry Andric 13104eeddc0SDimitry Andric return AddUnmappedPath(Path, Group, isFramework, UserEntryIdx); 13204eeddc0SDimitry Andric } 13304eeddc0SDimitry Andric 13404eeddc0SDimitry Andric bool InitHeaderSearch::AddUnmappedPath(const Twine &Path, IncludeDirGroup Group, 13504eeddc0SDimitry Andric bool isFramework, 136bdd1243dSDimitry Andric std::optional<unsigned> UserEntryIdx) { 13704eeddc0SDimitry Andric assert(!Path.isTriviallyEmpty() && "can't handle empty path here"); 13804eeddc0SDimitry Andric 13904eeddc0SDimitry Andric FileManager &FM = Headers.getFileMgr(); 14004eeddc0SDimitry Andric SmallString<256> MappedPathStorage; 14104eeddc0SDimitry Andric StringRef MappedPathStr = Path.toStringRef(MappedPathStorage); 14204eeddc0SDimitry Andric 14304eeddc0SDimitry Andric // If use system headers while cross-compiling, emit the warning. 144*5f757f3fSDimitry Andric if (HasSysroot && (MappedPathStr.starts_with("/usr/include") || 145*5f757f3fSDimitry Andric MappedPathStr.starts_with("/usr/local/include"))) { 14604eeddc0SDimitry Andric Headers.getDiags().Report(diag::warn_poison_system_directories) 14704eeddc0SDimitry Andric << MappedPathStr; 14804eeddc0SDimitry Andric } 14904eeddc0SDimitry Andric 15004eeddc0SDimitry Andric // Compute the DirectoryLookup type. 15104eeddc0SDimitry Andric SrcMgr::CharacteristicKind Type; 15204eeddc0SDimitry Andric if (Group == Quoted || Group == Angled || Group == IndexHeaderMap) { 15304eeddc0SDimitry Andric Type = SrcMgr::C_User; 15404eeddc0SDimitry Andric } else if (Group == ExternCSystem) { 15504eeddc0SDimitry Andric Type = SrcMgr::C_ExternCSystem; 15604eeddc0SDimitry Andric } else { 15704eeddc0SDimitry Andric Type = SrcMgr::C_System; 15804eeddc0SDimitry Andric } 15904eeddc0SDimitry Andric 16004eeddc0SDimitry Andric // If the directory exists, add it. 16104eeddc0SDimitry Andric if (auto DE = FM.getOptionalDirectoryRef(MappedPathStr)) { 16204eeddc0SDimitry Andric IncludePath.emplace_back(Group, DirectoryLookup(*DE, Type, isFramework), 16304eeddc0SDimitry Andric UserEntryIdx); 16404eeddc0SDimitry Andric return true; 16504eeddc0SDimitry Andric } 16604eeddc0SDimitry Andric 16704eeddc0SDimitry Andric // Check to see if this is an apple-style headermap (which are not allowed to 16804eeddc0SDimitry Andric // be frameworks). 16904eeddc0SDimitry Andric if (!isFramework) { 170*5f757f3fSDimitry Andric if (auto FE = FM.getOptionalFileRef(MappedPathStr)) { 17104eeddc0SDimitry Andric if (const HeaderMap *HM = Headers.CreateHeaderMap(*FE)) { 17204eeddc0SDimitry Andric // It is a headermap, add it to the search path. 17304eeddc0SDimitry Andric IncludePath.emplace_back( 17404eeddc0SDimitry Andric Group, DirectoryLookup(HM, Type, Group == IndexHeaderMap), 17504eeddc0SDimitry Andric UserEntryIdx); 17604eeddc0SDimitry Andric return true; 17704eeddc0SDimitry Andric } 17804eeddc0SDimitry Andric } 17904eeddc0SDimitry Andric } 18004eeddc0SDimitry Andric 18104eeddc0SDimitry Andric if (Verbose) 18204eeddc0SDimitry Andric llvm::errs() << "ignoring nonexistent directory \"" 18304eeddc0SDimitry Andric << MappedPathStr << "\"\n"; 18404eeddc0SDimitry Andric return false; 18504eeddc0SDimitry Andric } 18604eeddc0SDimitry Andric 18704eeddc0SDimitry Andric void InitHeaderSearch::AddMinGWCPlusPlusIncludePaths(StringRef Base, 18804eeddc0SDimitry Andric StringRef Arch, 18904eeddc0SDimitry Andric StringRef Version) { 19004eeddc0SDimitry Andric AddPath(Base + "/" + Arch + "/" + Version + "/include/c++", 19104eeddc0SDimitry Andric CXXSystem, false); 19204eeddc0SDimitry Andric AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/" + Arch, 19304eeddc0SDimitry Andric CXXSystem, false); 19404eeddc0SDimitry Andric AddPath(Base + "/" + Arch + "/" + Version + "/include/c++/backward", 19504eeddc0SDimitry Andric CXXSystem, false); 19604eeddc0SDimitry Andric } 19704eeddc0SDimitry Andric 19804eeddc0SDimitry Andric void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple, 19904eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts) { 200bdd1243dSDimitry Andric if (!ShouldAddDefaultIncludePaths(triple)) 20104eeddc0SDimitry Andric llvm_unreachable("Include management is handled in the driver."); 202bdd1243dSDimitry Andric 203bdd1243dSDimitry Andric llvm::Triple::OSType os = triple.getOS(); 20404eeddc0SDimitry Andric 20504eeddc0SDimitry Andric if (HSOpts.UseStandardSystemIncludes) { 20604eeddc0SDimitry Andric switch (os) { 20704eeddc0SDimitry Andric case llvm::Triple::Win32: 20804eeddc0SDimitry Andric if (triple.getEnvironment() != llvm::Triple::Cygnus) 20904eeddc0SDimitry Andric break; 210bdd1243dSDimitry Andric [[fallthrough]]; 21104eeddc0SDimitry Andric default: 21204eeddc0SDimitry Andric // FIXME: temporary hack: hard-coded paths. 21304eeddc0SDimitry Andric AddPath("/usr/local/include", System, false); 21404eeddc0SDimitry Andric break; 21504eeddc0SDimitry Andric } 21604eeddc0SDimitry Andric } 21704eeddc0SDimitry Andric 21804eeddc0SDimitry Andric // Builtin includes use #include_next directives and should be positioned 21904eeddc0SDimitry Andric // just prior C include dirs. 22004eeddc0SDimitry Andric if (HSOpts.UseBuiltinIncludes) { 22104eeddc0SDimitry Andric // Ignore the sys root, we *always* look for clang headers relative to 22204eeddc0SDimitry Andric // supplied path. 22304eeddc0SDimitry Andric SmallString<128> P = StringRef(HSOpts.ResourceDir); 22404eeddc0SDimitry Andric llvm::sys::path::append(P, "include"); 22504eeddc0SDimitry Andric AddUnmappedPath(P, ExternCSystem, false); 22604eeddc0SDimitry Andric } 22704eeddc0SDimitry Andric 22804eeddc0SDimitry Andric // All remaining additions are for system include directories, early exit if 22904eeddc0SDimitry Andric // we aren't using them. 23004eeddc0SDimitry Andric if (!HSOpts.UseStandardSystemIncludes) 23104eeddc0SDimitry Andric return; 23204eeddc0SDimitry Andric 23304eeddc0SDimitry Andric // Add dirs specified via 'configure --with-c-include-dirs'. 23404eeddc0SDimitry Andric StringRef CIncludeDirs(C_INCLUDE_DIRS); 23504eeddc0SDimitry Andric if (CIncludeDirs != "") { 23604eeddc0SDimitry Andric SmallVector<StringRef, 5> dirs; 23704eeddc0SDimitry Andric CIncludeDirs.split(dirs, ":"); 23804eeddc0SDimitry Andric for (StringRef dir : dirs) 23904eeddc0SDimitry Andric AddPath(dir, ExternCSystem, false); 24004eeddc0SDimitry Andric return; 24104eeddc0SDimitry Andric } 24204eeddc0SDimitry Andric 24304eeddc0SDimitry Andric switch (os) { 24404eeddc0SDimitry Andric case llvm::Triple::Win32: 24504eeddc0SDimitry Andric switch (triple.getEnvironment()) { 24604eeddc0SDimitry Andric default: llvm_unreachable("Include management is handled in the driver."); 24704eeddc0SDimitry Andric case llvm::Triple::Cygnus: 24804eeddc0SDimitry Andric AddPath("/usr/include/w32api", System, false); 24904eeddc0SDimitry Andric break; 25004eeddc0SDimitry Andric case llvm::Triple::GNU: 25104eeddc0SDimitry Andric break; 25204eeddc0SDimitry Andric } 25304eeddc0SDimitry Andric break; 25404eeddc0SDimitry Andric default: 25504eeddc0SDimitry Andric break; 25604eeddc0SDimitry Andric } 25704eeddc0SDimitry Andric 25804eeddc0SDimitry Andric AddPath("/usr/include", ExternCSystem, false); 25904eeddc0SDimitry Andric } 26004eeddc0SDimitry Andric 26104eeddc0SDimitry Andric void InitHeaderSearch::AddDefaultCPlusPlusIncludePaths( 26204eeddc0SDimitry Andric const LangOptions &LangOpts, const llvm::Triple &triple, 26304eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts) { 264bdd1243dSDimitry Andric if (!ShouldAddDefaultIncludePaths(triple)) 265bdd1243dSDimitry Andric llvm_unreachable("Include management is handled in the driver."); 266bdd1243dSDimitry Andric 26704eeddc0SDimitry Andric // FIXME: temporary hack: hard-coded paths. 268bdd1243dSDimitry Andric llvm::Triple::OSType os = triple.getOS(); 26904eeddc0SDimitry Andric switch (os) { 27004eeddc0SDimitry Andric case llvm::Triple::Win32: 27104eeddc0SDimitry Andric switch (triple.getEnvironment()) { 27204eeddc0SDimitry Andric default: llvm_unreachable("Include management is handled in the driver."); 27304eeddc0SDimitry Andric case llvm::Triple::Cygnus: 27404eeddc0SDimitry Andric // Cygwin-1.7 27504eeddc0SDimitry Andric AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.7.3"); 27604eeddc0SDimitry Andric AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.5.3"); 27704eeddc0SDimitry Andric AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.4"); 27804eeddc0SDimitry Andric // g++-4 / Cygwin-1.5 27904eeddc0SDimitry Andric AddMinGWCPlusPlusIncludePaths("/usr/lib/gcc", "i686-pc-cygwin", "4.3.2"); 28004eeddc0SDimitry Andric break; 28104eeddc0SDimitry Andric } 28204eeddc0SDimitry Andric break; 28304eeddc0SDimitry Andric default: 28404eeddc0SDimitry Andric break; 28504eeddc0SDimitry Andric } 28604eeddc0SDimitry Andric } 28704eeddc0SDimitry Andric 288bdd1243dSDimitry Andric bool InitHeaderSearch::ShouldAddDefaultIncludePaths( 289bdd1243dSDimitry Andric const llvm::Triple &triple) { 29004eeddc0SDimitry Andric switch (triple.getOS()) { 291bdd1243dSDimitry Andric case llvm::Triple::AIX: 292*5f757f3fSDimitry Andric case llvm::Triple::DragonFly: 293*5f757f3fSDimitry Andric case llvm::Triple::ELFIAMCU: 29404eeddc0SDimitry Andric case llvm::Triple::Emscripten: 295bdd1243dSDimitry Andric case llvm::Triple::FreeBSD: 296*5f757f3fSDimitry Andric case llvm::Triple::Fuchsia: 297*5f757f3fSDimitry Andric case llvm::Triple::Haiku: 298*5f757f3fSDimitry Andric case llvm::Triple::Hurd: 299*5f757f3fSDimitry Andric case llvm::Triple::Linux: 300*5f757f3fSDimitry Andric case llvm::Triple::LiteOS: 301*5f757f3fSDimitry Andric case llvm::Triple::NaCl: 302bdd1243dSDimitry Andric case llvm::Triple::NetBSD: 30304eeddc0SDimitry Andric case llvm::Triple::OpenBSD: 30406c3fb27SDimitry Andric case llvm::Triple::PS4: 30506c3fb27SDimitry Andric case llvm::Triple::PS5: 306*5f757f3fSDimitry Andric case llvm::Triple::RTEMS: 30704eeddc0SDimitry Andric case llvm::Triple::Solaris: 30804eeddc0SDimitry Andric case llvm::Triple::WASI: 309*5f757f3fSDimitry Andric case llvm::Triple::ZOS: 310bdd1243dSDimitry Andric return false; 31104eeddc0SDimitry Andric 31204eeddc0SDimitry Andric case llvm::Triple::Win32: 31304eeddc0SDimitry Andric if (triple.getEnvironment() != llvm::Triple::Cygnus || 31404eeddc0SDimitry Andric triple.isOSBinFormatMachO()) 315bdd1243dSDimitry Andric return false; 31604eeddc0SDimitry Andric break; 31704eeddc0SDimitry Andric 31804eeddc0SDimitry Andric case llvm::Triple::UnknownOS: 31904eeddc0SDimitry Andric if (triple.isWasm()) 320bdd1243dSDimitry Andric return false; 321bdd1243dSDimitry Andric break; 322bdd1243dSDimitry Andric 323bdd1243dSDimitry Andric default: 32404eeddc0SDimitry Andric break; 32504eeddc0SDimitry Andric } 32604eeddc0SDimitry Andric 327bdd1243dSDimitry Andric return true; // Everything else uses AddDefaultIncludePaths(). 328bdd1243dSDimitry Andric } 329bdd1243dSDimitry Andric 330bdd1243dSDimitry Andric void InitHeaderSearch::AddDefaultIncludePaths( 331bdd1243dSDimitry Andric const LangOptions &Lang, const llvm::Triple &triple, 332bdd1243dSDimitry Andric const HeaderSearchOptions &HSOpts) { 333bdd1243dSDimitry Andric // NB: This code path is going away. All of the logic is moving into the 334bdd1243dSDimitry Andric // driver which has the information necessary to do target-specific 335bdd1243dSDimitry Andric // selections of default include paths. Each target which moves there will be 336bdd1243dSDimitry Andric // exempted from this logic in ShouldAddDefaultIncludePaths() until we can 337bdd1243dSDimitry Andric // delete the entire pile of code. 338bdd1243dSDimitry Andric if (!ShouldAddDefaultIncludePaths(triple)) 339bdd1243dSDimitry Andric return; 340bdd1243dSDimitry Andric 341bdd1243dSDimitry Andric // NOTE: some additional header search logic is handled in the driver for 342bdd1243dSDimitry Andric // Darwin. 34304eeddc0SDimitry Andric if (triple.isOSDarwin()) { 34404eeddc0SDimitry Andric if (HSOpts.UseStandardSystemIncludes) { 34504eeddc0SDimitry Andric // Add the default framework include paths on Darwin. 346bdd1243dSDimitry Andric if (triple.isDriverKit()) { 347bdd1243dSDimitry Andric AddPath("/System/DriverKit/System/Library/Frameworks", System, true); 348bdd1243dSDimitry Andric } else { 34904eeddc0SDimitry Andric AddPath("/System/Library/Frameworks", System, true); 35004eeddc0SDimitry Andric AddPath("/Library/Frameworks", System, true); 35104eeddc0SDimitry Andric } 352bdd1243dSDimitry Andric } 35304eeddc0SDimitry Andric return; 35404eeddc0SDimitry Andric } 35504eeddc0SDimitry Andric 35604eeddc0SDimitry Andric if (Lang.CPlusPlus && !Lang.AsmPreprocessor && 35704eeddc0SDimitry Andric HSOpts.UseStandardCXXIncludes && HSOpts.UseStandardSystemIncludes) { 35804eeddc0SDimitry Andric if (HSOpts.UseLibcxx) { 35904eeddc0SDimitry Andric AddPath("/usr/include/c++/v1", CXXSystem, false); 36004eeddc0SDimitry Andric } else { 36104eeddc0SDimitry Andric AddDefaultCPlusPlusIncludePaths(Lang, triple, HSOpts); 36204eeddc0SDimitry Andric } 36304eeddc0SDimitry Andric } 36404eeddc0SDimitry Andric 36504eeddc0SDimitry Andric AddDefaultCIncludePaths(triple, HSOpts); 36604eeddc0SDimitry Andric } 36704eeddc0SDimitry Andric 368bdd1243dSDimitry Andric /// If there are duplicate directory entries in the specified search list, 369bdd1243dSDimitry Andric /// remove the later (dead) ones. Returns the number of non-system headers 370bdd1243dSDimitry Andric /// removed, which is used to update NumAngled. 37104eeddc0SDimitry Andric static unsigned RemoveDuplicates(std::vector<DirectoryLookupInfo> &SearchList, 37204eeddc0SDimitry Andric unsigned First, bool Verbose) { 37304eeddc0SDimitry Andric llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenDirs; 37404eeddc0SDimitry Andric llvm::SmallPtrSet<const DirectoryEntry *, 8> SeenFrameworkDirs; 37504eeddc0SDimitry Andric llvm::SmallPtrSet<const HeaderMap *, 8> SeenHeaderMaps; 37604eeddc0SDimitry Andric unsigned NonSystemRemoved = 0; 37704eeddc0SDimitry Andric for (unsigned i = First; i != SearchList.size(); ++i) { 37804eeddc0SDimitry Andric unsigned DirToRemove = i; 37904eeddc0SDimitry Andric 38004eeddc0SDimitry Andric const DirectoryLookup &CurEntry = SearchList[i].Lookup; 38104eeddc0SDimitry Andric 38204eeddc0SDimitry Andric if (CurEntry.isNormalDir()) { 38304eeddc0SDimitry Andric // If this isn't the first time we've seen this dir, remove it. 38404eeddc0SDimitry Andric if (SeenDirs.insert(CurEntry.getDir()).second) 38504eeddc0SDimitry Andric continue; 38604eeddc0SDimitry Andric } else if (CurEntry.isFramework()) { 38704eeddc0SDimitry Andric // If this isn't the first time we've seen this framework dir, remove it. 38804eeddc0SDimitry Andric if (SeenFrameworkDirs.insert(CurEntry.getFrameworkDir()).second) 38904eeddc0SDimitry Andric continue; 39004eeddc0SDimitry Andric } else { 39104eeddc0SDimitry Andric assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); 39204eeddc0SDimitry Andric // If this isn't the first time we've seen this headermap, remove it. 39304eeddc0SDimitry Andric if (SeenHeaderMaps.insert(CurEntry.getHeaderMap()).second) 39404eeddc0SDimitry Andric continue; 39504eeddc0SDimitry Andric } 39604eeddc0SDimitry Andric 39704eeddc0SDimitry Andric // If we have a normal #include dir/framework/headermap that is shadowed 39804eeddc0SDimitry Andric // later in the chain by a system include location, we actually want to 39904eeddc0SDimitry Andric // ignore the user's request and drop the user dir... keeping the system 40004eeddc0SDimitry Andric // dir. This is weird, but required to emulate GCC's search path correctly. 40104eeddc0SDimitry Andric // 40204eeddc0SDimitry Andric // Since dupes of system dirs are rare, just rescan to find the original 40304eeddc0SDimitry Andric // that we're nuking instead of using a DenseMap. 40404eeddc0SDimitry Andric if (CurEntry.getDirCharacteristic() != SrcMgr::C_User) { 40504eeddc0SDimitry Andric // Find the dir that this is the same of. 40604eeddc0SDimitry Andric unsigned FirstDir; 40704eeddc0SDimitry Andric for (FirstDir = First;; ++FirstDir) { 40804eeddc0SDimitry Andric assert(FirstDir != i && "Didn't find dupe?"); 40904eeddc0SDimitry Andric 41004eeddc0SDimitry Andric const DirectoryLookup &SearchEntry = SearchList[FirstDir].Lookup; 41104eeddc0SDimitry Andric 41204eeddc0SDimitry Andric // If these are different lookup types, then they can't be the dupe. 41304eeddc0SDimitry Andric if (SearchEntry.getLookupType() != CurEntry.getLookupType()) 41404eeddc0SDimitry Andric continue; 41504eeddc0SDimitry Andric 41604eeddc0SDimitry Andric bool isSame; 41704eeddc0SDimitry Andric if (CurEntry.isNormalDir()) 41804eeddc0SDimitry Andric isSame = SearchEntry.getDir() == CurEntry.getDir(); 41904eeddc0SDimitry Andric else if (CurEntry.isFramework()) 42004eeddc0SDimitry Andric isSame = SearchEntry.getFrameworkDir() == CurEntry.getFrameworkDir(); 42104eeddc0SDimitry Andric else { 42204eeddc0SDimitry Andric assert(CurEntry.isHeaderMap() && "Not a headermap or normal dir?"); 42304eeddc0SDimitry Andric isSame = SearchEntry.getHeaderMap() == CurEntry.getHeaderMap(); 42404eeddc0SDimitry Andric } 42504eeddc0SDimitry Andric 42604eeddc0SDimitry Andric if (isSame) 42704eeddc0SDimitry Andric break; 42804eeddc0SDimitry Andric } 42904eeddc0SDimitry Andric 43004eeddc0SDimitry Andric // If the first dir in the search path is a non-system dir, zap it 43104eeddc0SDimitry Andric // instead of the system one. 43204eeddc0SDimitry Andric if (SearchList[FirstDir].Lookup.getDirCharacteristic() == SrcMgr::C_User) 43304eeddc0SDimitry Andric DirToRemove = FirstDir; 43404eeddc0SDimitry Andric } 43504eeddc0SDimitry Andric 43604eeddc0SDimitry Andric if (Verbose) { 43704eeddc0SDimitry Andric llvm::errs() << "ignoring duplicate directory \"" 43804eeddc0SDimitry Andric << CurEntry.getName() << "\"\n"; 43904eeddc0SDimitry Andric if (DirToRemove != i) 44004eeddc0SDimitry Andric llvm::errs() << " as it is a non-system directory that duplicates " 44104eeddc0SDimitry Andric << "a system directory\n"; 44204eeddc0SDimitry Andric } 44304eeddc0SDimitry Andric if (DirToRemove != i) 44404eeddc0SDimitry Andric ++NonSystemRemoved; 44504eeddc0SDimitry Andric 44604eeddc0SDimitry Andric // This is reached if the current entry is a duplicate. Remove the 44704eeddc0SDimitry Andric // DirToRemove (usually the current dir). 44804eeddc0SDimitry Andric SearchList.erase(SearchList.begin()+DirToRemove); 44904eeddc0SDimitry Andric --i; 45004eeddc0SDimitry Andric } 45104eeddc0SDimitry Andric return NonSystemRemoved; 45204eeddc0SDimitry Andric } 45304eeddc0SDimitry Andric 45404eeddc0SDimitry Andric /// Extract DirectoryLookups from DirectoryLookupInfos. 45504eeddc0SDimitry Andric static std::vector<DirectoryLookup> 45604eeddc0SDimitry Andric extractLookups(const std::vector<DirectoryLookupInfo> &Infos) { 45704eeddc0SDimitry Andric std::vector<DirectoryLookup> Lookups; 45804eeddc0SDimitry Andric Lookups.reserve(Infos.size()); 45904eeddc0SDimitry Andric llvm::transform(Infos, std::back_inserter(Lookups), 46004eeddc0SDimitry Andric [](const DirectoryLookupInfo &Info) { return Info.Lookup; }); 46104eeddc0SDimitry Andric return Lookups; 46204eeddc0SDimitry Andric } 46304eeddc0SDimitry Andric 46404eeddc0SDimitry Andric /// Collect the mapping between indices of DirectoryLookups and UserEntries. 46504eeddc0SDimitry Andric static llvm::DenseMap<unsigned, unsigned> 46604eeddc0SDimitry Andric mapToUserEntries(const std::vector<DirectoryLookupInfo> &Infos) { 46704eeddc0SDimitry Andric llvm::DenseMap<unsigned, unsigned> LookupsToUserEntries; 46804eeddc0SDimitry Andric for (unsigned I = 0, E = Infos.size(); I < E; ++I) { 46904eeddc0SDimitry Andric // Check whether this DirectoryLookup maps to a HeaderSearch::UserEntry. 47004eeddc0SDimitry Andric if (Infos[I].UserEntryIdx) 47104eeddc0SDimitry Andric LookupsToUserEntries.insert({I, *Infos[I].UserEntryIdx}); 47204eeddc0SDimitry Andric } 47304eeddc0SDimitry Andric return LookupsToUserEntries; 47404eeddc0SDimitry Andric } 47504eeddc0SDimitry Andric 47604eeddc0SDimitry Andric void InitHeaderSearch::Realize(const LangOptions &Lang) { 47704eeddc0SDimitry Andric // Concatenate ANGLE+SYSTEM+AFTER chains together into SearchList. 47804eeddc0SDimitry Andric std::vector<DirectoryLookupInfo> SearchList; 47904eeddc0SDimitry Andric SearchList.reserve(IncludePath.size()); 48004eeddc0SDimitry Andric 48104eeddc0SDimitry Andric // Quoted arguments go first. 48204eeddc0SDimitry Andric for (auto &Include : IncludePath) 48304eeddc0SDimitry Andric if (Include.Group == Quoted) 48404eeddc0SDimitry Andric SearchList.push_back(Include); 48504eeddc0SDimitry Andric 48604eeddc0SDimitry Andric // Deduplicate and remember index. 48704eeddc0SDimitry Andric RemoveDuplicates(SearchList, 0, Verbose); 48804eeddc0SDimitry Andric unsigned NumQuoted = SearchList.size(); 48904eeddc0SDimitry Andric 49004eeddc0SDimitry Andric for (auto &Include : IncludePath) 49104eeddc0SDimitry Andric if (Include.Group == Angled || Include.Group == IndexHeaderMap) 49204eeddc0SDimitry Andric SearchList.push_back(Include); 49304eeddc0SDimitry Andric 49404eeddc0SDimitry Andric RemoveDuplicates(SearchList, NumQuoted, Verbose); 49504eeddc0SDimitry Andric unsigned NumAngled = SearchList.size(); 49604eeddc0SDimitry Andric 49704eeddc0SDimitry Andric for (auto &Include : IncludePath) 49804eeddc0SDimitry Andric if (Include.Group == System || Include.Group == ExternCSystem || 49904eeddc0SDimitry Andric (!Lang.ObjC && !Lang.CPlusPlus && Include.Group == CSystem) || 50004eeddc0SDimitry Andric (/*FIXME !Lang.ObjC && */ Lang.CPlusPlus && 50104eeddc0SDimitry Andric Include.Group == CXXSystem) || 50204eeddc0SDimitry Andric (Lang.ObjC && !Lang.CPlusPlus && Include.Group == ObjCSystem) || 50304eeddc0SDimitry Andric (Lang.ObjC && Lang.CPlusPlus && Include.Group == ObjCXXSystem)) 50404eeddc0SDimitry Andric SearchList.push_back(Include); 50504eeddc0SDimitry Andric 50604eeddc0SDimitry Andric for (auto &Include : IncludePath) 50704eeddc0SDimitry Andric if (Include.Group == After) 50804eeddc0SDimitry Andric SearchList.push_back(Include); 50904eeddc0SDimitry Andric 51004eeddc0SDimitry Andric // Remove duplicates across both the Angled and System directories. GCC does 51104eeddc0SDimitry Andric // this and failing to remove duplicates across these two groups breaks 51204eeddc0SDimitry Andric // #include_next. 51304eeddc0SDimitry Andric unsigned NonSystemRemoved = RemoveDuplicates(SearchList, NumQuoted, Verbose); 51404eeddc0SDimitry Andric NumAngled -= NonSystemRemoved; 51504eeddc0SDimitry Andric 51604eeddc0SDimitry Andric Headers.SetSearchPaths(extractLookups(SearchList), NumQuoted, NumAngled, 517*5f757f3fSDimitry Andric mapToUserEntries(SearchList)); 51804eeddc0SDimitry Andric 51904eeddc0SDimitry Andric Headers.SetSystemHeaderPrefixes(SystemHeaderPrefixes); 52004eeddc0SDimitry Andric 52104eeddc0SDimitry Andric // If verbose, print the list of directories that will be searched. 52204eeddc0SDimitry Andric if (Verbose) { 52304eeddc0SDimitry Andric llvm::errs() << "#include \"...\" search starts here:\n"; 52404eeddc0SDimitry Andric for (unsigned i = 0, e = SearchList.size(); i != e; ++i) { 52504eeddc0SDimitry Andric if (i == NumQuoted) 52604eeddc0SDimitry Andric llvm::errs() << "#include <...> search starts here:\n"; 52704eeddc0SDimitry Andric StringRef Name = SearchList[i].Lookup.getName(); 52804eeddc0SDimitry Andric const char *Suffix; 52904eeddc0SDimitry Andric if (SearchList[i].Lookup.isNormalDir()) 53004eeddc0SDimitry Andric Suffix = ""; 53104eeddc0SDimitry Andric else if (SearchList[i].Lookup.isFramework()) 53204eeddc0SDimitry Andric Suffix = " (framework directory)"; 53304eeddc0SDimitry Andric else { 53404eeddc0SDimitry Andric assert(SearchList[i].Lookup.isHeaderMap() && "Unknown DirectoryLookup"); 53504eeddc0SDimitry Andric Suffix = " (headermap)"; 53604eeddc0SDimitry Andric } 53704eeddc0SDimitry Andric llvm::errs() << " " << Name << Suffix << "\n"; 53804eeddc0SDimitry Andric } 53904eeddc0SDimitry Andric llvm::errs() << "End of search list.\n"; 54004eeddc0SDimitry Andric } 54104eeddc0SDimitry Andric } 54204eeddc0SDimitry Andric 54304eeddc0SDimitry Andric void clang::ApplyHeaderSearchOptions(HeaderSearch &HS, 54404eeddc0SDimitry Andric const HeaderSearchOptions &HSOpts, 54504eeddc0SDimitry Andric const LangOptions &Lang, 54604eeddc0SDimitry Andric const llvm::Triple &Triple) { 54704eeddc0SDimitry Andric InitHeaderSearch Init(HS, HSOpts.Verbose, HSOpts.Sysroot); 54804eeddc0SDimitry Andric 54904eeddc0SDimitry Andric // Add the user defined entries. 55004eeddc0SDimitry Andric for (unsigned i = 0, e = HSOpts.UserEntries.size(); i != e; ++i) { 55104eeddc0SDimitry Andric const HeaderSearchOptions::Entry &E = HSOpts.UserEntries[i]; 55204eeddc0SDimitry Andric if (E.IgnoreSysRoot) { 55304eeddc0SDimitry Andric Init.AddUnmappedPath(E.Path, E.Group, E.IsFramework, i); 55404eeddc0SDimitry Andric } else { 55504eeddc0SDimitry Andric Init.AddPath(E.Path, E.Group, E.IsFramework, i); 55604eeddc0SDimitry Andric } 55704eeddc0SDimitry Andric } 55804eeddc0SDimitry Andric 55904eeddc0SDimitry Andric Init.AddDefaultIncludePaths(Lang, Triple, HSOpts); 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric for (unsigned i = 0, e = HSOpts.SystemHeaderPrefixes.size(); i != e; ++i) 56204eeddc0SDimitry Andric Init.AddSystemHeaderPrefix(HSOpts.SystemHeaderPrefixes[i].Prefix, 56304eeddc0SDimitry Andric HSOpts.SystemHeaderPrefixes[i].IsSystemHeader); 56404eeddc0SDimitry Andric 56504eeddc0SDimitry Andric if (HSOpts.UseBuiltinIncludes) { 56604eeddc0SDimitry Andric // Set up the builtin include directory in the module map. 56704eeddc0SDimitry Andric SmallString<128> P = StringRef(HSOpts.ResourceDir); 56804eeddc0SDimitry Andric llvm::sys::path::append(P, "include"); 56906c3fb27SDimitry Andric if (auto Dir = HS.getFileMgr().getOptionalDirectoryRef(P)) 57004eeddc0SDimitry Andric HS.getModuleMap().setBuiltinIncludeDir(*Dir); 57104eeddc0SDimitry Andric } 57204eeddc0SDimitry Andric 57304eeddc0SDimitry Andric Init.Realize(Lang); 57404eeddc0SDimitry Andric } 575