Skip to content

Commit 99664ba

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 97e17e1 commit 99664ba

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
@@ -847,6 +847,9 @@ def note_drv_available_multilibs : Note<
847847
"available multilibs are:%0">;
848848
def err_drv_multilib_custom_error : Error<
849849
"multilib configuration error: %0">;
850+
def warn_drv_multilib_not_available_for_target: Warning<
851+
"no multilib structure encoded for Arm, Aarch64 and PPC targets">,
852+
InGroup<DiagGroup<"multilib-not-found">>;
850853

851854
def err_drv_experimental_crel : Error<
852855
"-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
@@ -31,6 +31,40 @@ using namespace clang::driver;
3131
using namespace clang::driver::tools;
3232
using namespace clang::driver::toolchains;
3333

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

98-
static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
132+
static std::string computeClangRuntimesSysRoot(const Driver &D,
133+
bool IncludeTriple) {
99134
if (!D.SysRoot.empty())
100135
return D.SysRoot;
101136

@@ -108,56 +143,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
108143
return std::string(SysRootDir);
109144
}
110145

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

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

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

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

151-
if (Triple.getOS() != llvm::Triple::UnknownOS)
152-
return false;
205+
// Use the clang-runtimes path.
206+
return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true);
207+
}
153208

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

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

163265
static void
@@ -216,7 +318,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
216318
return {};
217319
}
218320
} else {
219-
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false);
321+
MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
220322
llvm::sys::path::append(MultilibPath, MultilibFilename);
221323
}
222324
return MultilibPath;
@@ -234,15 +336,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
234336
if (D.getVFS().exists(*MultilibPath)) {
235337
// If multilib.yaml is found, update sysroot so it doesn't use a target
236338
// specific suffix
237-
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false);
339+
SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false);
238340
SmallVector<StringRef> CustomFlagMacroDefines;
239341
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result,
240342
CustomFlagMacroDefines);
241343
SelectedMultilibs = Result.SelectedMultilibs;
242344
Multilibs = Result.Multilibs;
243345
MultilibMacroDefines.append(CustomFlagMacroDefines.begin(),
244346
CustomFlagMacroDefines.end());
245-
} else if (isRISCVBareMetal(Triple)) {
347+
} else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) {
246348
if (findRISCVMultilibs(D, Triple, Args, Result)) {
247349
SelectedMultilibs = Result.SelectedMultilibs;
248350
Multilibs = Result.Multilibs;
@@ -263,8 +365,6 @@ Tool *BareMetal::buildStaticLibTool() const {
263365
return new tools::baremetal::StaticLibTool(*this);
264366
}
265367

266-
std::string BareMetal::computeSysRoot() const { return SysRoot; }
267-
268368
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const {
269369
// Get multilibs in reverse order because they're ordered most-specific last.
270370
if (!SelectedMultilibs.empty())
@@ -292,10 +392,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
292392
if (std::optional<std::string> Path = getStdlibIncludePath())
293393
addSystemInclude(DriverArgs, CC1Args, *Path);
294394

295-
const SmallString<128> SysRoot(computeSysRoot());
296-
if (!SysRoot.empty()) {
395+
const SmallString<128> SysRootDir(computeSysRoot());
396+
if (!SysRootDir.empty()) {
297397
for (const Multilib &M : getOrderedMultilibs()) {
298-
SmallString<128> Dir(SysRoot);
398+
SmallString<128> Dir(SysRootDir);
299399
llvm::sys::path::append(Dir, M.includeSuffix());
300400
llvm::sys::path::append(Dir, "include");
301401
addSystemInclude(DriverArgs, CC1Args, Dir.str());
@@ -309,6 +409,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
309409
CC1Args.push_back("-nostdsysteminc");
310410
}
311411

412+
void BareMetal::addLibStdCxxIncludePaths(
413+
const llvm::opt::ArgList &DriverArgs,
414+
llvm::opt::ArgStringList &CC1Args) const {
415+
if (!IsGCCInstallationValid)
416+
return;
417+
const GCCVersion &Version = GCCInstallation.getVersion();
418+
StringRef TripleStr = GCCInstallation.getTriple().str();
419+
const Multilib &Multilib = GCCInstallation.getMultilib();
420+
addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text,
421+
TripleStr, Multilib.includeSuffix(), DriverArgs,
422+
CC1Args);
423+
}
424+
312425
void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
313426
ArgStringList &CC1Args) const {
314427
if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -339,23 +452,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
339452
};
340453

341454
switch (GetCXXStdlibType(DriverArgs)) {
342-
case ToolChain::CST_Libcxx: {
343-
SmallString<128> P(D.Dir);
344-
llvm::sys::path::append(P, "..", "include");
345-
AddCXXIncludePath(P);
346-
break;
347-
}
348-
case ToolChain::CST_Libstdcxx:
349-
// We only support libc++ toolchain installation.
350-
break;
455+
case ToolChain::CST_Libcxx: {
456+
SmallString<128> P(D.Dir);
457+
llvm::sys::path::append(P, "..", "include");
458+
AddCXXIncludePath(P);
459+
break;
460+
}
461+
case ToolChain::CST_Libstdcxx:
462+
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
463+
break;
351464
}
352465

353-
std::string SysRoot(computeSysRoot());
354-
if (SysRoot.empty())
466+
std::string SysRootDir(computeSysRoot());
467+
if (SysRootDir.empty())
355468
return;
356469

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

0 commit comments

Comments
 (0)