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