Skip to content

Commit f19e2e0

Browse files
committed
[Driver] Teach Barmetal toolchain about GCC installation
This patch introduces the baretmetal toolchain object about GCC Installation. Currently, if `--gcc-installation` ot `--gcc-install-dir` options are passed on commandline, then sysroot will be formed from there if paths will be valid. Otherwise, it will be fallback to as it already existed in the Baremetal toolchaibn object. Moreover, support for adding include paths for libstd C++ library is added as well. Additionally, the restriction to always use integrated assembler is removed because with valid gcc installation, gnu assembler can be invoked as well. This patch currently adds and modifies arm related test only. The riscv specific test will be added in the last PR when driver code related to calling of RISCVToolchain object will be removed. Currently in this PR, there is no way to test riscv target. RFC: https://discourse.llvm.org/t/merging-riscvtoolchain-and-baremetal-toolchains/75524 Change-Id: Ibaeb569cf7e2cee03c022aa9ecd1abe29d5c30d4
1 parent 6263de9 commit f19e2e0

File tree

32 files changed

+418
-64
lines changed

32 files changed

+418
-64
lines changed

clang/docs/Toolchain.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,8 @@ workarounds for issues discovered in libstdc++, and these are removed
347347
as fixed libstdc++ becomes sufficiently old.
348348

349349
You can instruct Clang to use libstdc++ with the ``-stdlib=libstdc++`` flag.
350+
351+
GCC Installation
352+
=================
353+
Users can point to their GCC installation by using the ``-gcc-toolchain`` or by
354+
using ``-gcc-install-dir`` flag.

clang/include/clang/Basic/DiagnosticDriverKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,9 @@ def note_drv_available_multilibs : Note<
830830
"available multilibs are:%0">;
831831
def err_drv_multilib_custom_error : Error<
832832
"multilib configuration error: %0">;
833+
def warn_drv_multilib_not_available_for_target: Warning<
834+
"no multilib structure encoded for Arm, Aarch64 and PPC targets">,
835+
InGroup<DiagGroup<"multilib-not-found">>;
833836

834837
def err_drv_experimental_crel : Error<
835838
"-Wa,--allow-experimental-crel must be specified to use -Wa,--crel. "

clang/lib/Driver/ToolChains/BareMetal.cpp

Lines changed: 174 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,40 @@ using namespace clang::driver;
3333
using namespace clang::driver::tools;
3434
using namespace clang::driver::toolchains;
3535

36+
/// Is the triple {aarch64.aarch64_be}-none-elf?
37+
static bool isAArch64BareMetal(const llvm::Triple &Triple) {
38+
if (Triple.getArch() != llvm::Triple::aarch64 &&
39+
Triple.getArch() != llvm::Triple::aarch64_be)
40+
return false;
41+
42+
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
43+
return false;
44+
45+
if (Triple.getOS() != llvm::Triple::UnknownOS)
46+
return false;
47+
48+
return Triple.getEnvironmentName() == "elf";
49+
}
50+
51+
static bool isRISCVBareMetal(const llvm::Triple &Triple) {
52+
if (!Triple.isRISCV())
53+
return false;
54+
55+
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
56+
return false;
57+
58+
if (Triple.getOS() != llvm::Triple::UnknownOS)
59+
return false;
60+
61+
return Triple.getEnvironmentName() == "elf";
62+
}
63+
64+
/// Is the triple powerpc[64][le]-*-none-eabi?
65+
static bool isPPCBareMetal(const llvm::Triple &Triple) {
66+
return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
67+
Triple.getEnvironment() == llvm::Triple::EABI;
68+
}
69+
3670
static bool findRISCVMultilibs(const Driver &D,
3771
const llvm::Triple &TargetTriple,
3872
const ArgList &Args, DetectedMultilibs &Result) {
@@ -97,7 +131,8 @@ static bool findRISCVMultilibs(const Driver &D,
97131
return false;
98132
}
99133

100-
static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
134+
static std::string computeClangRuntimesSysRoot(const Driver &D,
135+
bool IncludeTriple) {
101136
if (!D.SysRoot.empty())
102137
return D.SysRoot;
103138

@@ -110,56 +145,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
110145
return std::string(SysRootDir);
111146
}
112147

113-
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
114-
const ArgList &Args)
115-
: ToolChain(D, Triple, Args),
116-
SysRoot(computeBaseSysRoot(D, /*IncludeTriple=*/true)) {
117-
getProgramPaths().push_back(getDriver().Dir);
118-
119-
findMultilibs(D, Triple, Args);
120-
SmallString<128> SysRoot(computeSysRoot());
121-
if (!SysRoot.empty()) {
122-
for (const Multilib &M : getOrderedMultilibs()) {
123-
SmallString<128> Dir(SysRoot);
124-
llvm::sys::path::append(Dir, M.osSuffix(), "lib");
125-
getFilePaths().push_back(std::string(Dir));
126-
getLibraryPaths().push_back(std::string(Dir));
127-
}
148+
// Only consider the GCC toolchain based on the values provided through the
149+
// `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns
150+
// whether the GCC toolchain was initialized successfully.
151+
bool BareMetal::initGCCInstallation(const llvm::Triple &Triple,
152+
const llvm::opt::ArgList &Args) {
153+
if (Args.getLastArg(options::OPT_gcc_toolchain) ||
154+
Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ)) {
155+
GCCInstallation.init(Triple, Args);
156+
return GCCInstallation.isValid();
128157
}
158+
return false;
129159
}
130160

131-
/// Is the triple {aarch64.aarch64_be}-none-elf?
132-
static bool isAArch64BareMetal(const llvm::Triple &Triple) {
133-
if (Triple.getArch() != llvm::Triple::aarch64 &&
134-
Triple.getArch() != llvm::Triple::aarch64_be)
135-
return false;
136-
137-
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
138-
return false;
139-
140-
if (Triple.getOS() != llvm::Triple::UnknownOS)
141-
return false;
142-
143-
return Triple.getEnvironmentName() == "elf";
161+
// This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort
162+
// to merge RISCVToolChain into the Baremetal toolchain. It infers the presence
163+
// of a valid GCC toolchain by checking whether the `crt0.o` file exists in the
164+
// `bin/../<target-triple>/lib` directory.
165+
static bool detectGCCToolchainAdjacent(const Driver &D) {
166+
SmallString<128> GCCDir;
167+
llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(),
168+
"lib/crt0.o");
169+
return llvm::sys::fs::exists(GCCDir);
144170
}
145171

146-
static bool isRISCVBareMetal(const llvm::Triple &Triple) {
147-
if (!Triple.isRISCV())
148-
return false;
172+
// If no sysroot is provided the driver will first attempt to infer it from the
173+
// values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the
174+
// location of a GCC toolchain.
175+
// If neither flag is used, the sysroot defaults to either:
176+
//    - `bin/../<target-triple>`
177+
//    - `bin/../lib/clang-runtimes/<target-triple>`
178+
//
179+
// To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o`
180+
// does not exist relative to the driver.
181+
std::string BareMetal::computeSysRoot() const {
182+
// Use Baremetal::sysroot if it has already been set.
183+
if (!SysRoot.empty())
184+
return SysRoot;
185+
186+
// Use the sysroot specified via the `--sysroot` command-line flag, if
187+
// provided.
188+
const Driver &D = getDriver();
189+
if (!D.SysRoot.empty())
190+
return D.SysRoot;
149191

150-
if (Triple.getVendor() != llvm::Triple::UnknownVendor)
151-
return false;
192+
// Attempt to infer sysroot from a valid GCC installation.
193+
// If no valid GCC installation, check for a GCC toolchain alongside Clang.
194+
SmallString<128> inferredSysRoot;
195+
if (IsGCCInstallationValid) {
196+
llvm::sys::path::append(inferredSysRoot, GCCInstallation.getParentLibPath(),
197+
"..", GCCInstallation.getTriple().str());
198+
} else if (detectGCCToolchainAdjacent(D)) {
199+
// Use the triple as provided to the driver. Unlike the parsed triple
200+
// this has not been normalized to always contain every field.
201+
llvm::sys::path::append(inferredSysRoot, D.Dir, "..", D.getTargetTriple());
202+
}
203+
// If a valid sysroot was inferred and exists, use it
204+
if (!inferredSysRoot.empty() && llvm::sys::fs::exists(inferredSysRoot))
205+
return std::string(inferredSysRoot);
152206

153-
if (Triple.getOS() != llvm::Triple::UnknownOS)
154-
return false;
207+
// Use the clang-runtimes path.
208+
return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);
209+
}
155210

156-
return Triple.getEnvironmentName() == "elf";
211+
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
212+
const Multilib &Multilib,
213+
StringRef InstallPath,
214+
ToolChain::path_list &Paths) {
215+
if (const auto &PathsCallback = Multilibs.filePathsCallback())
216+
for (const auto &Path : PathsCallback(Multilib))
217+
addPathIfExists(D, InstallPath + Path, Paths);
157218
}
158219

159-
/// Is the triple powerpc[64][le]-*-none-eabi?
160-
static bool isPPCBareMetal(const llvm::Triple &Triple) {
161-
return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS &&
162-
Triple.getEnvironment() == llvm::Triple::EABI;
220+
// GCC mutltilibs will only work for those targets that have their multlib
221+
// structure encoded into GCCInstallation. Baremetal toolchain supports ARM,
222+
// AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded
223+
// in GCCInstallation.
224+
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple,
225+
const ArgList &Args)
226+
: Generic_ELF(D, Triple, Args) {
227+
IsGCCInstallationValid = initGCCInstallation(Triple, Args);
228+
std::string ComputedSysRoot = computeSysRoot();
229+
if (IsGCCInstallationValid) {
230+
if (!isRISCVBareMetal(Triple))
231+
D.Diag(clang::diag::warn_drv_multilib_not_available_for_target);
232+
233+
Multilibs = GCCInstallation.getMultilibs();
234+
SelectedMultilibs.assign({GCCInstallation.getMultilib()});
235+
236+
path_list &Paths = getFilePaths();
237+
// Add toolchain/multilib specific file paths.
238+
addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
239+
GCCInstallation.getInstallPath(), Paths);
240+
// Adding filepath for locating crt{begin,end}.o files.
241+
Paths.push_back(GCCInstallation.getInstallPath().str());
242+
// Adding filepath for locating crt0.o file.
243+
Paths.push_back(ComputedSysRoot + "/lib");
244+
245+
ToolChain::path_list &PPaths = getProgramPaths();
246+
// Multilib cross-compiler GCC installations put ld in a triple-prefixed
247+
// directory off of the parent of the GCC installation.
248+
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
249+
GCCInstallation.getTriple().str() + "/bin")
250+
.str());
251+
PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
252+
} else {
253+
getProgramPaths().push_back(getDriver().Dir);
254+
findMultilibs(D, Triple, Args);
255+
const SmallString<128> SysRootDir(computeSysRoot());
256+
if (!SysRootDir.empty()) {
257+
for (const Multilib &M : getOrderedMultilibs()) {
258+
SmallString<128> Dir(SysRootDir);
259+
llvm::sys::path::append(Dir, M.osSuffix(), "lib");
260+
getFilePaths().push_back(std::string(Dir));
261+
getLibraryPaths().push_back(std::string(Dir));
262+
}
263+
}
264+
}
163265
}
164266

165267
static void
@@ -218,7 +320,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
218320
return {};
219321
}
220322
} else {
221-
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
323+
MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
222324
llvm::sys::path::append(MultilibPath, MultilibFilename);
223325
}
224326
return MultilibPath;
@@ -236,15 +338,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
236338
if (D.getVFS().exists(*MultilibPath)) {
237339
// If multilib.yaml is found, update sysroot so it doesn't use a target
238340
// specific suffix
239-
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
341+
SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
240342
SmallVector<StringRef> CustomFlagMacroDefines;
241343
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result,
242344
CustomFlagMacroDefines);
243345
SelectedMultilibs = Result.SelectedMultilibs;
244346
Multilibs = Result.Multilibs;
245347
MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),
246348
CustomFlagMacroDefines.end());
247-
} else if (isRISCVBareMetal(Triple)) {
349+
} else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
248350
if (findRISCVMultilibs(D, Triple, Args, Result)) {
249351
SelectedMultilibs = Result.SelectedMultilibs;
250352
Multilibs = Result.Multilibs;
@@ -265,8 +367,6 @@ Tool *BareMetal::buildStaticLibTool() const {
265367
return new tools::baremetal::StaticLibTool(*this);
266368
}
267369

268-
std::string BareMetal::computeSysRoot() const { return SysRoot; }
269-
270370
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
271371
// Get multilibs in reverse order because they're ordered most-specific last.
272372
if (!SelectedMultilibs.empty())
@@ -294,10 +394,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
294394
if (std::optional<std::string> Path = getStdlibIncludePath())
295395
addSystemInclude(DriverArgs, CC1Args, *Path);
296396

297-
const SmallString<128> SysRoot(computeSysRoot());
298-
if (!SysRoot.empty()) {
397+
const SmallString<128> SysRootDir(computeSysRoot());
398+
if (!SysRootDir.empty()) {
299399
for (const Multilib &M : getOrderedMultilibs()) {
300-
SmallString<128> Dir(SysRoot);
400+
SmallString<128> Dir(SysRootDir);
301401
llvm::sys::path::append(Dir, M.includeSuffix());
302402
llvm::sys::path::append(Dir, "include");
303403
addSystemInclude(DriverArgs, CC1Args, Dir.str());
@@ -311,6 +411,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
311411
CC1Args.push_back("-nostdsysteminc");
312412
}
313413

414+
void BareMetal::addLibStdCxxIncludePaths(
415+
const llvm::opt::ArgList &DriverArgs,
416+
llvm::opt::ArgStringList &CC1Args) const {
417+
if (!IsGCCInstallationValid)
418+
return;
419+
const GCCVersion &Version = GCCInstallation.getVersion();
420+
StringRef TripleStr = GCCInstallation.getTriple().str();
421+
const Multilib &Multilib = GCCInstallation.getMultilib();
422+
addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
423+
TripleStr, Multilib.includeSuffix(), DriverArgs,
424+
CC1Args);
425+
}
426+
314427
void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
315428
ArgStringList &CC1Args) const {
316429
if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -341,23 +454,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
341454
};
342455

343456
switch (GetCXXStdlibType(DriverArgs)) {
344-
case ToolChain::CST_Libcxx: {
345-
SmallString<128> P(D.Dir);
346-
llvm::sys::path::append(P, "..", "include");
347-
AddCXXIncludePath(P);
348-
break;
349-
}
350-
case ToolChain::CST_Libstdcxx:
351-
// We only support libc++ toolchain installation.
352-
break;
457+
case ToolChain::CST_Libcxx: {
458+
SmallString<128> P(D.Dir);
459+
llvm::sys::path::append(P, "..", "include");
460+
AddCXXIncludePath(P);
461+
break;
462+
}
463+
case ToolChain::CST_Libstdcxx:
464+
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
465+
break;
353466
}
354467

355-
std::string SysRoot(computeSysRoot());
356-
if (SysRoot.empty())
468+
std::string SysRootDir(computeSysRoot());
469+
if (SysRootDir.empty())
357470
return;
358471

359472
for (const Multilib &M : getOrderedMultilibs()) {
360-
SmallString<128> Dir(SysRoot);
473+
SmallString<128> Dir(SysRootDir);
361474
llvm::sys::path::append(Dir, M.gccSuffix());
362475
switch (GetCXXStdlibType(DriverArgs)) {
363476
case ToolChain::CST_Libcxx: {

0 commit comments

Comments
 (0)