Skip to content

Commit a32a2b2

Browse files
authored
[clang][driver] Add <executable>/../include/c++/v1 to include path on Darwin (#70817)
On macOS, when clang is invoked via a symlink, since the InstalledDir is where the link is located, the C++ headers are not identified and the default system headers from the SDK are used. This can be undesirable if a toolchain is created by symlinking clang into a directory and placing libc++ headers in that directory with the intent of those headers overriding the SDK headers. This change solves that problem by also looking for libc++ headers in the toolchain-relative location of the executable symlink, if any.
1 parent 197f305 commit a32a2b2

File tree

2 files changed

+82
-7
lines changed

2 files changed

+82
-7
lines changed

clang/lib/Driver/ToolChains/Darwin.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2470,14 +2470,19 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
24702470

24712471
switch (GetCXXStdlibType(DriverArgs)) {
24722472
case ToolChain::CST_Libcxx: {
2473-
// On Darwin, libc++ can be installed in one of the following two places:
2474-
// 1. Alongside the compiler in <install>/include/c++/v1
2475-
// 2. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
2473+
// On Darwin, libc++ can be installed in one of the following places:
2474+
// 1. Alongside the compiler in <install>/include/c++/v1
2475+
// 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1
2476+
// 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
24762477
//
2477-
// The precendence of paths is as listed above, i.e. we take the first path
2478-
// that exists. Also note that we never include libc++ twice -- we take the
2479-
// first path that exists and don't send the other paths to CC1 (otherwise
2478+
// The precedence of paths is as listed above, i.e. we take the first path
2479+
// that exists. Note that we never include libc++ twice -- we take the first
2480+
// path that exists and don't send the other paths to CC1 (otherwise
24802481
// include_next could break).
2482+
//
2483+
// Also note that in most cases, (1) and (2) are exactly the same path.
2484+
// Those two paths will differ only when the `clang` program being run
2485+
// is actually a symlink to the real executable.
24812486

24822487
// Check for (1)
24832488
// Get from '<install>/bin' to '<install>/include/c++/v1'.
@@ -2494,7 +2499,20 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
24942499
<< "\"\n";
24952500
}
24962501

2497-
// Otherwise, check for (2)
2502+
// (2) Check for the folder where the executable is located, if different.
2503+
if (getDriver().getInstalledDir() != getDriver().Dir) {
2504+
InstallBin = llvm::StringRef(getDriver().Dir);
2505+
llvm::sys::path::append(InstallBin, "..", "include", "c++", "v1");
2506+
if (getVFS().exists(InstallBin)) {
2507+
addSystemInclude(DriverArgs, CC1Args, InstallBin);
2508+
return;
2509+
} else if (DriverArgs.hasArg(options::OPT_v)) {
2510+
llvm::errs() << "ignoring nonexistent directory \"" << InstallBin
2511+
<< "\"\n";
2512+
}
2513+
}
2514+
2515+
// Otherwise, check for (3)
24982516
llvm::SmallString<128> SysrootUsr = Sysroot;
24992517
llvm::sys::path::append(SysrootUsr, "usr", "include", "c++", "v1");
25002518
if (getVFS().exists(SysrootUsr)) {

clang/test/Driver/darwin-header-search-libcxx.cpp

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,3 +172,60 @@
172172
// RUN: --check-prefix=CHECK-LIBCXX-STDLIB-UNSPECIFIED %s
173173
// CHECK-LIBCXX-STDLIB-UNSPECIFIED: "-cc1"
174174
// CHECK-LIBCXX-STDLIB-UNSPECIFIED: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
175+
176+
// ----------------------------------------------------------------------------
177+
// On Darwin, libc++ can be installed in one of the following places:
178+
// 1. Alongside the compiler in <install>/include/c++/v1
179+
// 2. Alongside the compiler in <clang-executable-folder>/../include/c++/v1
180+
// 3. In a SDK (or a custom sysroot) in <sysroot>/usr/include/c++/v1
181+
182+
// The build folders do not have an `include/c++/v1`; create a new
183+
// local folder hierarchy that meets this requirement.
184+
// Note: this might not work with weird RPATH configurations.
185+
// RUN: rm -rf %t/install
186+
// RUN: mkdir -pv %t/install/bin
187+
// RUN: cp %clang %t/install/bin/clang
188+
// RUN: mkdir -pv %t/install/include/c++/v1
189+
190+
// Headers in (1) and in (2) -> (1) is preferred over (2)
191+
// RUN: rm -rf %t/symlinked1
192+
// RUN: mkdir -pv %t/symlinked1/bin
193+
// RUN: ln -svf %t/install/bin/clang %t/symlinked1/bin/clang
194+
// RUN: mkdir -pv %t/symlinked1/include/c++/v1
195+
196+
// RUN: %t/symlinked1/bin/clang -### %s -fsyntax-only 2>&1 \
197+
// RUN: --target=x86_64-apple-darwin \
198+
// RUN: -stdlib=libc++ \
199+
// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
200+
// RUN: | FileCheck -DSYMLINKED=%t/symlinked1 \
201+
// RUN: -DTOOLCHAIN=%t/install \
202+
// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
203+
// RUN: --check-prefix=CHECK-SYMLINKED-INCLUDE-CXX-V1 %s
204+
// CHECK-SYMLINKED-INCLUDE-CXX-V1: "-internal-isystem" "[[SYMLINKED]]/bin/../include/c++/v1"
205+
// CHECK-SYMLINKED-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1"
206+
// CHECK-SYMLINKED-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
207+
208+
// Headers in (2) and in (3) -> (2) is preferred over (3)
209+
// RUN: rm -rf %t/symlinked2
210+
// RUN: mkdir -pv %t/symlinked2/bin
211+
// RUN: ln -svf %t/install/bin/clang %t/symlinked2/bin/clang
212+
213+
// RUN: %t/symlinked2/bin/clang -### %s -fsyntax-only 2>&1 \
214+
// RUN: --target=x86_64-apple-darwin \
215+
// RUN: -stdlib=libc++ \
216+
// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
217+
// RUN: | FileCheck -DTOOLCHAIN=%t/install \
218+
// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
219+
// RUN: --check-prefix=CHECK-TOOLCHAIN-INCLUDE-CXX-V1 %s
220+
// CHECK-TOOLCHAIN-INCLUDE-CXX-V1: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1"
221+
// CHECK-TOOLCHAIN-INCLUDE-CXX-V1-NOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
222+
223+
// Headers in (2) and nowhere else -> (2) is used
224+
// RUN: %t/symlinked2/bin/clang -### %s -fsyntax-only 2>&1 \
225+
// RUN: --target=x86_64-apple-darwin \
226+
// RUN: -stdlib=libc++ \
227+
// RUN: -isysroot %S/Inputs/basic_darwin_sdk_usr_cxx_v1 \
228+
// RUN: | FileCheck -DTOOLCHAIN=%t/install \
229+
// RUN: -DSYSROOT=%S/Inputs/basic_darwin_sdk_no_libcxx \
230+
// RUN: --check-prefix=CHECK-TOOLCHAIN-NO-SYSROOT %s
231+
// CHECK-TOOLCHAIN-NO-SYSROOT: "-internal-isystem" "[[TOOLCHAIN]]/bin/../include/c++/v1"

0 commit comments

Comments
 (0)