Skip to content

Commit b07e771

Browse files
authored
Merge pull request swiftlang#4761 from apple/egorzhdan/linux-sysroot-slash_20211026
🍒[Clang][Driver] Fix include paths for `--sysroot /` on Linux
2 parents 3cb7b37 + c69436e commit b07e771

File tree

7 files changed

+75
-34
lines changed

7 files changed

+75
-34
lines changed

clang/include/clang/Driver/ToolChain.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,9 @@ class ToolChain {
211211
static void addSystemIncludes(const llvm::opt::ArgList &DriverArgs,
212212
llvm::opt::ArgStringList &CC1Args,
213213
ArrayRef<StringRef> Paths);
214+
215+
static std::string concat(StringRef Path, const Twine &A, const Twine &B = "",
216+
const Twine &C = "", const Twine &D = "");
214217
///@}
215218

216219
public:

clang/lib/Driver/ToolChain.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,14 @@ void ToolChain::addExternCSystemIncludeIfExists(const ArgList &DriverArgs,
876876
}
877877
}
878878

879+
/*static*/ std::string ToolChain::concat(StringRef Path, const Twine &A,
880+
const Twine &B, const Twine &C,
881+
const Twine &D) {
882+
SmallString<128> Result(Path);
883+
llvm::sys::path::append(Result, llvm::sys::path::Style::posix, A, B, C, D);
884+
return std::string(Result);
885+
}
886+
879887
std::string ToolChain::detectLibcxxVersion(StringRef IncludePath) const {
880888
std::error_code EC;
881889
int MaxVersion = 0;

clang/lib/Driver/ToolChains/Gnu.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,7 +1957,7 @@ void Generic_GCC::GCCInstallationDetector::init(
19571957
if (!VFS.exists(Prefix))
19581958
continue;
19591959
for (StringRef Suffix : CandidateLibDirs) {
1960-
const std::string LibDir = Prefix + Suffix.str();
1960+
const std::string LibDir = concat(Prefix, Suffix);
19611961
if (!VFS.exists(LibDir))
19621962
continue;
19631963
// Maybe filter out <libdir>/gcc and <libdir>/gcc-cross.
@@ -2023,7 +2023,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
20232023
// so we need to find those /usr/gcc/*/lib/gcc libdirs and go with
20242024
// /usr/gcc/<version> as a prefix.
20252025

2026-
std::string PrefixDir = SysRoot.str() + "/usr/gcc";
2026+
std::string PrefixDir = concat(SysRoot, "/usr/gcc");
20272027
std::error_code EC;
20282028
for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC),
20292029
LE;
@@ -2058,7 +2058,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
20582058
Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
20592059
Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
20602060
}
2061-
Prefixes.push_back(SysRoot.str() + "/usr");
2061+
Prefixes.push_back(concat(SysRoot, "/usr"));
20622062
}
20632063

20642064
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
@@ -2571,7 +2571,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooConfigs(
25712571
const llvm::Triple &TargetTriple, const ArgList &Args,
25722572
const SmallVectorImpl<StringRef> &CandidateTriples,
25732573
const SmallVectorImpl<StringRef> &CandidateBiarchTriples) {
2574-
if (!D.getVFS().exists(D.SysRoot + GentooConfigDir))
2574+
if (!D.getVFS().exists(concat(D.SysRoot, GentooConfigDir)))
25752575
return false;
25762576

25772577
for (StringRef CandidateTriple : CandidateTriples) {
@@ -2590,8 +2590,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
25902590
const llvm::Triple &TargetTriple, const ArgList &Args,
25912591
StringRef CandidateTriple, bool NeedsBiarchSuffix) {
25922592
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
2593-
D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/config-" +
2594-
CandidateTriple.str());
2593+
D.getVFS().getBufferForFile(concat(D.SysRoot, GentooConfigDir,
2594+
"/config-" + CandidateTriple.str()));
25952595
if (File) {
25962596
SmallVector<StringRef, 2> Lines;
25972597
File.get()->getBuffer().split(Lines, "\n");
@@ -2602,8 +2602,8 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
26022602
continue;
26032603
// Process the config file pointed to by CURRENT.
26042604
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> ConfigFile =
2605-
D.getVFS().getBufferForFile(D.SysRoot + GentooConfigDir + "/" +
2606-
Line.str());
2605+
D.getVFS().getBufferForFile(
2606+
concat(D.SysRoot, GentooConfigDir, "/" + Line));
26072607
std::pair<StringRef, StringRef> ActiveVersion = Line.rsplit('-');
26082608
// List of paths to scan for libraries.
26092609
SmallVector<StringRef, 4> GentooScanPaths;
@@ -2636,7 +2636,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
26362636

26372637
// Scan all paths for GCC libraries.
26382638
for (const auto &GentooScanPath : GentooScanPaths) {
2639-
std::string GentooPath = D.SysRoot + std::string(GentooScanPath);
2639+
std::string GentooPath = concat(D.SysRoot, GentooScanPath);
26402640
if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
26412641
if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
26422642
NeedsBiarchSuffix))
@@ -2922,9 +2922,9 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
29222922
// If this is a development, non-installed, clang, libcxx will
29232923
// not be found at ../include/c++ but it likely to be found at
29242924
// one of the following two locations:
2925-
if (AddIncludePath(SysRoot + "/usr/local/include"))
2925+
if (AddIncludePath(concat(SysRoot, "/usr/local/include")))
29262926
return;
2927-
if (AddIncludePath(SysRoot + "/usr/include"))
2927+
if (AddIncludePath(concat(SysRoot, "/usr/include")))
29282928
return;
29292929
}
29302930

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 23 additions & 22 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:
@@ -263,8 +263,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
263263

264264
Generic_GCC::AddMultilibPaths(D, SysRoot, OSLibDir, MultiarchTriple, Paths);
265265

266-
addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths);
267-
addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths);
266+
addPathIfExists(D, concat(SysRoot, "/lib", MultiarchTriple), Paths);
267+
addPathIfExists(D, concat(SysRoot, "/lib/..", OSLibDir), Paths);
268268

269269
if (IsAndroid) {
270270
// Android sysroots contain a library directory for each supported OS
@@ -275,24 +275,24 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
275275
unsigned Micro;
276276
Triple.getEnvironmentVersion(Major, Minor, Micro);
277277
addPathIfExists(D,
278-
SysRoot + "/usr/lib/" + MultiarchTriple + "/" +
279-
llvm::to_string(Major),
278+
concat(SysRoot, "/usr/lib", MultiarchTriple,
279+
llvm::to_string(Major)),
280280
Paths);
281281
}
282282

283-
addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths);
283+
addPathIfExists(D, concat(SysRoot, "/usr/lib", MultiarchTriple), Paths);
284284
// 64-bit OpenEmbedded sysroots may not have a /usr/lib dir. So they cannot
285285
// find /usr/lib64 as it is referenced as /usr/lib/../lib64. So we handle
286286
// this here.
287287
if (Triple.getVendor() == llvm::Triple::OpenEmbedded &&
288288
Triple.isArch64Bit())
289-
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir, Paths);
289+
addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir), Paths);
290290
else
291-
addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths);
291+
addPathIfExists(D, concat(SysRoot, "/usr/lib/..", OSLibDir), Paths);
292292
if (IsRISCV) {
293293
StringRef ABIName = tools::riscv::getRISCVABI(Args, Triple);
294-
addPathIfExists(D, SysRoot + "/" + OSLibDir + "/" + ABIName, Paths);
295-
addPathIfExists(D, SysRoot + "/usr/" + OSLibDir + "/" + ABIName, Paths);
294+
addPathIfExists(D, concat(SysRoot, "/", OSLibDir, ABIName), Paths);
295+
addPathIfExists(D, concat(SysRoot, "/usr", OSLibDir, ABIName), Paths);
296296
}
297297

298298
Generic_GCC::AddMultiarchPaths(D, SysRoot, OSLibDir, Paths);
@@ -310,8 +310,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
310310
addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths);
311311
}
312312

313-
addPathIfExists(D, SysRoot + "/lib", Paths);
314-
addPathIfExists(D, SysRoot + "/usr/lib", Paths);
313+
addPathIfExists(D, concat(SysRoot, "/lib"), Paths);
314+
addPathIfExists(D, concat(SysRoot, "/usr/lib"), Paths);
315315
}
316316

317317
ToolChain::RuntimeLibType Linux::GetDefaultRuntimeLibType() const {
@@ -555,7 +555,7 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
555555
return;
556556

557557
// LOCAL_INCLUDE_DIR
558-
addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include");
558+
addSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/local/include"));
559559
// TOOL_INCLUDE_DIR
560560
AddMultilibIncludeArgs(DriverArgs, CC1Args);
561561

@@ -576,19 +576,20 @@ void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
576576
// /usr/include.
577577
std::string MultiarchIncludeDir = getMultiarchTriple(D, getTriple(), SysRoot);
578578
if (!MultiarchIncludeDir.empty() &&
579-
D.getVFS().exists(SysRoot + "/usr/include/" + MultiarchIncludeDir))
580-
addExternCSystemInclude(DriverArgs, CC1Args,
581-
SysRoot + "/usr/include/" + MultiarchIncludeDir);
579+
D.getVFS().exists(concat(SysRoot, "/usr/include", MultiarchIncludeDir)))
580+
addExternCSystemInclude(
581+
DriverArgs, CC1Args,
582+
concat(SysRoot, "/usr/include", MultiarchIncludeDir));
582583

583584
if (getTriple().getOS() == llvm::Triple::RTEMS)
584585
return;
585586

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

591-
addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include");
592+
addExternCSystemInclude(DriverArgs, CC1Args, concat(SysRoot, "/usr/include"));
592593

593594
if (!DriverArgs.hasArg(options::OPT_nobuiltininc) && getTriple().isMusl())
594595
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)