Skip to content

Commit 1b98795

Browse files
authored
Merge pull request #4762 from apple/egorzhdan/linux-sysroot-slash_20220421
🍒[Clang][Driver] Fix include paths for `--sysroot /` on Linux
2 parents c46d66a + 7a7dc5f commit 1b98795

File tree

7 files changed

+77
-36
lines changed

7 files changed

+77
-36
lines changed

clang/include/clang/Driver/ToolChain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,9 @@ class ToolChain {
213213
static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs,
214214
llvm::opt::ArgStringList &CC1Args,
215215
ArrayRef<StringRef> Paths);
216+
217+
static std::string concat(StringRef Path, const Twine &A, const Twine &B = "",
218+
const Twine &C = "", const Twine &D = "");
216219
///@}
217220

218221
public:

clang/lib/Driver/ToolChain.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
905905
}
906906
}
907907

908+
/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A,
909+
const Twine &B, const Twine &C,
910+
const Twine &D) {
911+
SmallString<128> Result(Path);
912+
llvm::sys::path::append(Result, llvm::sys::path::Style::posix, A, B, C, D);
913+
return std::string(Result);
914+
}
915+
908916
std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const {
909917
std::error_code EC;
910918
int MaxVersion = 0;

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,7 +2021,7 @@ void Generic_GCC::GCCInstallationDetector::init(
20212021
if (!VFS.exists(Prefix))
20222022
continue;
20232023
for (StringRef Suffix : CandidateLibDirs) {
2024-
const std::string LibDir = Prefix + Suffix.str();
2024+
const std::string LibDir = concat(Prefix, Suffix);
20252025
if (!VFS.exists(LibDir))
20262026
continue;
20272027
// Maybe filter out <libdir>/gcc and <libdir>/gcc-cross.
@@ -2087,7 +2087,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
20872087
// so we need to find those /usr/gcc/*/lib/gcc libdirs and go with
20882088
// /usr/gcc/<version> as a prefix.
20892089

2090-
std::string PrefixDir = SysRoot.str() + "/usr/gcc";
2090+
std::string PrefixDir = concat(SysRoot, "/usr/gcc");
20912091
std::error_code EC;
20922092
for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC),
20932093
LE;
@@ -2122,7 +2122,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
21222122
Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
21232123
Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
21242124
}
2125-
Prefixes.push_back(SysRoot.str() + "/usr");
2125+
Prefixes.push_back(concat(SysRoot, "/usr"));
21262126
}
21272127

21282128
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
@@ -2645,7 +2645,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
26452645
const llvm::Triple &TargetTriple, const ArgList &Args,
26462646
const SmallVectorImpl<StringRef> &CandidateTriples,
26472647
const SmallVectorImpl<StringRef> &CandidateBiarchTriples) {
2648-
if (!D.getVFS().exists(D.SysRoot + GentooConfigDir))
2648+
if (!D.getVFS().exists(concat(D.SysRoot, GentooConfigDir)))
26492649
return false;
26502650

26512651
for (StringRef CandidateTriple : CandidateTriples) {
@@ -2664,8 +2664,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
26642664
const llvm::Triple &TargetTriple, const ArgList &Args,
26652665
StringRef CandidateTriple, bool NeedsBiarchSuffix) {
26662666
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
2667-
D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/config-" +
2668-
CandidateTriple.str());
2667+
D.getVFS().getBufferForFile(concat(D.SysRoot, GentooConfigDir,
2668+
"/config-" + CandidateTriple.str()));
26692669
if (File) {
26702670
SmallVector<StringRef, 2> Lines;
26712671
File.get()->getBuffer().split(Lines, "\n");
@@ -2676,8 +2676,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
26762676
continue;
26772677
// Process the config file pointed to by CURRENT.
26782678
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile =
2679-
D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/" +
2680-
Line.str());
2679+
D.getVFS().getBufferForFile(
2680+
concat(D.SysRoot, GentooConfigDir, "/" + Line));
26812681
std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-');
26822682
// List of paths to scan for libraries.
26832683
SmallVector<StringRef, 4> GentooScanPaths;
@@ -2710,7 +2710,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
27102710

27112711
// Scan all paths for GCC libraries.
27122712
for (const auto &GentooScanPath : GentooScanPaths) {
2713-
std::string GentooPath = D.SysRoot + std::string(GentooScanPath);
2713+
std::string GentooPath = concat(D.SysRoot, GentooScanPath);
27142714
if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
27152715
if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
27162716
NeedsBiarchSuffix))
@@ -3003,9 +3003,9 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
30033003
// If this is a development, non-installed, clang, libcxx will
30043004
// not be found at ../include/c++ but it likely to be found at
30053005
// one of the following two locations:
3006-
if (AddIncludePath(SysRoot + "/usr/local/include"))
3006+
if (AddIncludePath(concat(SysRoot, "/usr/local/include")))
30073007
return;
3008-
if (AddIncludePath(SysRoot + "/usr/include"))
3008+
if (AddIncludePath(concat(SysRoot, "/usr/include")))
30093009
return;
30103010
}
30113011

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,9 @@ std::string Linux::getMultiarchTriple(const Driver &D,
9797
case llvm::Triple::mips64: {
9898
std::string MT = std::string(IsMipsR6 ? "mipsisa64r6" : "mips64") +
9999
"-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
100-
if (D.getVFS().exists(SysRoot + "/lib/" + MT))
100+
if (D.getVFS().exists(concat(SysRoot, "/lib", MT)))
101101
return MT;
102-
if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu"))
102+
if (D.getVFS().exists(concat(SysRoot, "/lib/mips64-linux-gnu")))
103103
return "mips64-linux-gnu";
104104
break;
105105
}
@@ -108,14 +108,14 @@ std::string Linux::getMultiarchTriple(const Driver &D,
108108
return "mips64el-linux-android";
109109
std::string MT = std::string(IsMipsR6 ? "mipsisa64r6el" : "mips64el") +
110110
"-linux-" + (IsMipsN32Abi ? "gnuabin32" : "gnuabi64");
111-
if (D.getVFS().exists(SysRoot + "/lib/" + MT))
111+
if (D.getVFS().exists(concat(SysRoot, "/lib", MT)))
112112
return MT;
113-
if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu"))
113+
if (D.getVFS().exists(concat(SysRoot, "/lib/mips64el-linux-gnu")))
114114
return "mips64el-linux-gnu";
115115
break;
116116
}
117117
case llvm::Triple::ppc:
118-
if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe"))
118+
if (D.getVFS().exists(concat(SysRoot, "/lib/powerpc-linux-gnuspe")))
119119
return "powerpc-linux-gnuspe";
120120
return "powerpc-linux-gnu";
121121
case llvm::Triple::ppcle:
@@ -269,38 +269,38 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
269269
// used. We need add both libo32 and /lib.
270270
if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel) {
271271
Generic_GCC::AddMultilibPaths(D, SysRoot, "libo32", MultiarchTriple, Paths);
272-
addPathIfExists(D, SysRoot + "/libo32", Paths);
273-
addPathIfExists(D, SysRoot + "/usr/libo32", Paths);
272+
addPathIfExists(D, concat(SysRoot, "/libo32"), Paths);
273+
addPathIfExists(D, concat(SysRoot, "/usr/libo32"), Paths);
274274
}
275275
Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);
276276

277-
addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
278-
addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
277+
addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths);
278+
addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths);
279279

280280
if (IsAndroid) {
281281
// Android sysroots contain a library directory for each supported OS
282282
// version as well as some unversioned libraries in the usual multiarch
283283
// directory.
284284
addPathIfExists(
285285
D,
286-
SysRoot + "/usr/lib/" + MultiarchTriple + "/" +
287-
llvm::to_string(Triple.getEnvironmentVersion().getMajor()),
286+
concat(SysRoot, "/usr/lib", MultiarchTriple,
287+
llvm::to_string(Triple.getEnvironmentVersion().getMajor())),
288288
Paths);
289289
}
290290

291-
addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
291+
addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);
292292
// 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot
293293
// find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle
294294
// this here.
295295
if (Triple.getVendor() == llvm::Triple::OpenEmbedded &&
296296
Triple.isArch64Bit())
297-
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths);
297+
addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);
298298
else
299-
addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
299+
addPathIfExists(D, concat(SysRoot, "/usr/lib/..", OSLibDir), Paths);
300300
if (IsRISCV) {
301301
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
302-
addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths);
303-
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths);
302+
addPathIfExists(D, concat(SysRoot, "/", OSLibDir, ABIName), Paths);
303+
addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir, ABIName), Paths);
304304
}
305305

306306
Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);
@@ -312,8 +312,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
312312
D.getVFS().exists(D.Dir + "/../lib/libc++.so"))
313313
addPathIfExists(D, D.Dir + "/../lib", Paths);
314314

315-
addPathIfExists(D, SysRoot + "/lib", Paths);
316-
addPathIfExists(D, SysRoot + "/usr/lib", Paths);
315+
addPathIfExists(D, concat(SysRoot, "/lib"), Paths);
316+
addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);
317317
}
318318

319319
ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
@@ -586,7 +586,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
586586
return;
587587

588588
// LOCAL_INCLUDE_DIR
589-
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
589+
addSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/local/include"));
590590
// TOOL_INCLUDE_DIR
591591
AddMultilibIncludeArgs(DriverArgs, CC1Args);
592592

@@ -607,19 +607,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
607607
// /usr/include.
608608
std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot);
609609
if (!MultiarchIncludeDir.empty() &&
610-
D.getVFS().exists(SysRoot + "/usr/include/" + MultiarchIncludeDir))
611-
addExternCSystemInclude(DriverArgs, CC1Args,
612-
SysRoot + "/usr/include/" + MultiarchIncludeDir);
610+
D.getVFS().exists(concat(SysRoot, "/usr/include", MultiarchIncludeDir)))
611+
addExternCSystemInclude(
612+
DriverArgs, CC1Args,
613+
concat(SysRoot, "/usr/include", MultiarchIncludeDir));
613614

614615
if (getTriple().getOS() == llvm::Triple::RTEMS)
615616
return;
616617

617618
// Add an include of '/include' directly. This isn't provided by default by
618619
// system GCCs, but is often used with cross-compiling GCCs, and harmless to
619620
// add even when Clang is acting as-if it were a system compiler.
620-
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include");
621+
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/include"));
621622

622-
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
623+
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));
623624

624625
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
625626
addSystemInclude(DriverArgs, CC1Args, ResourceDirInclude);

clang/test/Driver/Inputs/basic_linux_libstdcxx_tree/usr/bin/.keep

Whitespace-only changes.

clang/test/Driver/Inputs/basic_linux_libstdcxx_tree/usr/lib/gcc/x86_64-unknown-linux-gnu/4.8/crtbegin.o

Whitespace-only changes.

clang/test/Driver/linux-header-search.cpp

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,22 @@
1616
// CHECK-BASIC-LIBCXX-SYSROOT: "-internal-isystem" "[[SYSROOT]]/usr/include/x86_64-unknown-linux-gnu/c++/v1"
1717
// CHECK-BASIC-LIBCXX-SYSROOT: "-internal-isystem" "[[SYSROOT]]/usr/include/c++/v1"
1818
// CHECK-BASIC-LIBCXX-SYSROOT: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
19+
20+
// Test include paths when the sysroot path ends with `/`.
21+
// RUN: %clang -### %s -fsyntax-only 2>&1 \
22+
// RUN: --target=x86_64-unknown-linux-gnu \
23+
// RUN: -stdlib=libc++ \
24+
// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \
25+
// RUN: -resource-dir=%S/Inputs/resource_dir \
26+
// RUN: --sysroot=%S/Inputs/basic_linux_libcxx_tree/ \
27+
// RUN: --gcc-toolchain="" \
28+
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBCXX-SYSROOT-SLASH %s
29+
// CHECK-BASIC-LIBCXX-SYSROOT-SLASH: "-cc1"
30+
// CHECK-BASIC-LIBCXX-SYSROOT-SLASH-SAME: "-isysroot" "[[SYSROOT:[^"]+/]]"
31+
// CHECK-BASIC-LIBCXX-SYSROOT-SLASH-SAME: "-internal-isystem" "[[SYSROOT]]usr/include/x86_64-unknown-linux-gnu/c++/v1"
32+
// CHECK-BASIC-LIBCXX-SYSROOT-SLASH-SAME: "-internal-isystem" "[[SYSROOT]]usr/include/c++/v1"
33+
// CHECK-BASIC-LIBCXX-SYSROOT-SLASH-SAME: "-internal-isystem" "[[SYSROOT]]usr/local/include"
34+
1935
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
2036
// RUN: -target x86_64-unknown-linux-gnu \
2137
// RUN: -stdlib=libc++ \
@@ -56,7 +72,20 @@
5672
// CHECK-BASIC-LIBCXXV2-INSTALL: "-internal-isystem" "[[SYSROOT]]/usr/bin/../include/x86_64-unknown-linux-gnu/c++/v2"
5773
// CHECK-BASIC-LIBCXXV2-INSTALL: "-internal-isystem" "[[SYSROOT]]/usr/bin/../include/c++/v2"
5874
// CHECK-BASIC-LIBCXXV2-INSTALL: "-internal-isystem" "[[SYSROOT]]/usr/local/include"
59-
//
75+
76+
// Test Linux with libstdc++ when the sysroot path ends with `/`.
77+
// RUN: %clang -### %s -fsyntax-only 2>&1 \
78+
// RUN: --target=x86_64-unknown-linux-gnu \
79+
// RUN: -stdlib=libstdc++ \
80+
// RUN: -ccc-install-dir %S/Inputs/basic_linux_tree/usr/bin \
81+
// RUN: -resource-dir=%S/Inputs/resource_dir \
82+
// RUN: --sysroot=%S/Inputs/basic_linux_libstdcxx_tree/ \
83+
// RUN: --gcc-toolchain="" \
84+
// RUN: | FileCheck --check-prefix=CHECK-BASIC-LIBSTDCXX-SYSROOT-SLASH %s
85+
// CHECK-BASIC-LIBSTDCXX-SYSROOT-SLASH: "-cc1"
86+
// CHECK-BASIC-LIBSTDCXX-SYSROOT-SLASH-SAME: "-isysroot" "[[SYSROOT:[^"]+/]]"
87+
// CHECK-BASIC-LIBSTDCXX-SYSROOT-SLASH-SAME: "-internal-isystem" "[[SYSROOT]]usr/lib/gcc/x86_64-unknown-linux-gnu/4.8/../../../../x86_64-unknown-linux-gnu/include"
88+
6089
// Test Linux with both libc++ and libstdc++ installed.
6190
// RUN: %clang -no-canonical-prefixes %s -### -fsyntax-only 2>&1 \
6291
// RUN: -target x86_64-unknown-linux-gnu \

0 commit comments

Comments
 (0)