diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index 7481f6cab9a96..7c3d4982d8f6a 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -2470,14 +2470,19 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( switch (GetCXXStdlibType(DriverArgs)) { case ToolChain::CST_Libcxx: { - // On Darwin, libc++ can be installed in one of the following two places: - // 1. Alongside the compiler in /include/c++/v1 - // 2. In a SDK (or a custom sysroot) in /usr/include/c++/v1 + // On Darwin, libc++ can be installed in one of the following places: + // 1. Alongside the compiler in /include/c++/v1 + // 2. Alongside the compiler in /../include/c++/v1 + // 3. In a SDK (or a custom sysroot) in /usr/include/c++/v1 // - // The precendence of paths is as listed above, i.e. we take the first path - // that exists. Also note that we never include libc++ twice -- we take the - // first path that exists and don't send the other paths to CC1 (otherwise + // The precedence of paths is as listed above, i.e. we take the first path + // that exists. Note that we never include libc++ twice -- we take the first + // path that exists and don't send the other paths to CC1 (otherwise // include_next could break). + // + // Also note that in most cases, (1) and (2) are exactly the same path. + // Those two paths will differ only when the `clang` program being run + // is actually a symlink to the real executable. // Check for (1) // Get from '/bin' to '/include/c++/v1'. @@ -2494,7 +2499,20 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs( << "\"\n"; } - // Otherwise, check for (2) + // (2) Check for the folder where the executable is located, if different. + if (getDriver().getInstalledDir() != getDriver().Dir) { + InstallBin = llvm::StringRef(getDriver().Dir); + llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1"); + if (getVFS().exists(InstallBin)) { + addSystemInclude(DriverArgs, CC1Args, InstallBin); + return; + } else if (DriverArgs.hasArg(options::OPT_v)) { + llvm::errs() << "ignoring nonexistent directory \"" << InstallBin + << "\"\n"; + } + } + + // Otherwise, check for (3) llvm::SmallString<128> SysrootUsr = Sysroot; llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1"); if (getVFS().exists(SysrootUsr)) { diff --git a/clang/test/Driver/darwin-header-search-libcxx.cpp b/clang/test/Driver/darwin-header-search-libcxx.cpp index cc8ec9ceb89b3..8f530299d53c6 100644 --- a/clang/test/Driver/darwin-header-search-libcxx.cpp +++ b/clang/test/Driver/darwin-header-search-libcxx.cpp @@ -172,3 +172,60 @@ // RUN: --check-prefix=CHECK-LIBCXX-STDLIB-UNSPECIFIED %s // CHECK-LIBCXX-STDLIB-UNSPECIFIED: "-cc1" // CHECK-LIBCXX-STDLIB-UNSPECIFIED: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// ---------------------------------------------------------------------------- +// On Darwin, libc++ can be installed in one of the following places: +// 1. Alongside the compiler in /include/c++/v1 +// 2. Alongside the compiler in /../include/c++/v1 +// 3. In a SDK (or a custom sysroot) in /usr/include/c++/v1 + +// The build folders do not have an `include/c++/v1`; create a new +// local folder hierarchy that meets this requirement. +// Note: this might not work with weird RPATH configurations. +// RUN: rm -rf %t/install +// RUN: mkdir -pv %t/install/bin +// RUN: cp %clang %t/install/bin/clang +// RUN: mkdir -pv %t/install/include/c++/v1 + +// Headers in (1) and in (2) -> (1) is preferred over (2) +// RUN: rm -rf %t/symlinked1 +// RUN: mkdir -pv %t/symlinked1/bin +// RUN: ln -svf %t/install/bin/clang %t/symlinked1/bin/clang +// RUN: mkdir -pv %t/symlinked1/include/c++/v1 + +// RUN: %t/symlinked1/bin/clang -### %s -fsyntax-only 2>&1 \ +// RUN: --target=x86_64-apple-darwin \ +// RUN: -stdlib=libc++ \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DSYMLINKED=%t/symlinked1 \ +// RUN: -DTOOLCHAIN=%t/install \ +// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: --check-prefix=CHECK-SYMLINKED-INCLUDE-CXX-V1 %s +// CHECK-SYMLINKED-INCLUDE-CXX-V1: "-internal-isystem" "[[SYMLINKED]]/bin/../include/c++/v1" +// CHECK-SYMLINKED-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1" +// CHECK-SYMLINKED-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Headers in (2) and in (3) -> (2) is preferred over (3) +// RUN: rm -rf %t/symlinked2 +// RUN: mkdir -pv %t/symlinked2/bin +// RUN: ln -svf %t/install/bin/clang %t/symlinked2/bin/clang + +// RUN: %t/symlinked2/bin/clang -### %s -fsyntax-only 2>&1 \ +// RUN: --target=x86_64-apple-darwin \ +// RUN: -stdlib=libc++ \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DTOOLCHAIN=%t/install \ +// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: --check-prefix=CHECK-TOOLCHAIN-INCLUDE-CXX-V1 %s +// CHECK-TOOLCHAIN-INCLUDE-CXX-V1: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1" +// CHECK-TOOLCHAIN-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1" + +// Headers in (2) and nowhere else -> (2) is used +// RUN: %t/symlinked2/bin/clang -### %s -fsyntax-only 2>&1 \ +// RUN: --target=x86_64-apple-darwin \ +// RUN: -stdlib=libc++ \ +// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \ +// RUN: | FileCheck -DTOOLCHAIN=%t/install \ +// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \ +// RUN: --check-prefix=CHECK-TOOLCHAIN-NO-SYSROOT %s +// CHECK-TOOLCHAIN-NO-SYSROOT: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1"