@@ -33,6 +33,40 @@ using namespace clang::driver;
33
33
using namespace clang ::driver::tools;
34
34
using namespace clang ::driver::toolchains;
35
35
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
+
36
70
static bool findRISCVMultilibs (const Driver &D,
37
71
const llvm::Triple &TargetTriple,
38
72
const ArgList &Args, DetectedMultilibs &Result) {
@@ -97,7 +131,8 @@ static bool findRISCVMultilibs(const Driver &D,
97
131
return false ;
98
132
}
99
133
100
- static std::string computeBaseSysRoot (const Driver &D, bool IncludeTriple) {
134
+ static std::string computeClangRuntimesSysRoot (const Driver &D,
135
+ bool IncludeTriple) {
101
136
if (!D.SysRoot .empty ())
102
137
return D.SysRoot ;
103
138
@@ -110,56 +145,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
110
145
return std::string (SysRootDir);
111
146
}
112
147
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 ();
128
157
}
158
+ return false ;
129
159
}
130
160
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);
144
170
}
145
171
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 ;
149
191
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);
152
206
153
- if (Triple.getOS () != llvm::Triple::UnknownOS)
154
- return false ;
207
+ // Use the clang-runtimes path.
208
+ return computeClangRuntimesSysRoot (D, /* IncludeTriple*/ true );
209
+ }
155
210
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);
157
218
}
158
219
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
+ }
163
265
}
164
266
165
267
static void
@@ -218,7 +320,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
218
320
return {};
219
321
}
220
322
} else {
221
- MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
323
+ MultilibPath = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
222
324
llvm::sys::path::append (MultilibPath, MultilibFilename);
223
325
}
224
326
return MultilibPath;
@@ -236,15 +338,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
236
338
if (D.getVFS ().exists (*MultilibPath)) {
237
339
// If multilib.yaml is found, update sysroot so it doesn't use a target
238
340
// specific suffix
239
- SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
341
+ SysRoot = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
240
342
SmallVector<StringRef> CustomFlagMacroDefines;
241
343
findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result,
242
344
CustomFlagMacroDefines);
243
345
SelectedMultilibs = Result.SelectedMultilibs ;
244
346
Multilibs = Result.Multilibs ;
245
347
MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
246
348
CustomFlagMacroDefines.end ());
247
- } else if (isRISCVBareMetal (Triple)) {
349
+ } else if (isRISCVBareMetal (Triple) && ! detectGCCToolchainAdjacent (D) ) {
248
350
if (findRISCVMultilibs (D, Triple, Args, Result)) {
249
351
SelectedMultilibs = Result.SelectedMultilibs ;
250
352
Multilibs = Result.Multilibs ;
@@ -265,8 +367,6 @@ Tool *BareMetal::buildStaticLibTool() const {
265
367
return new tools::baremetal::StaticLibTool (*this );
266
368
}
267
369
268
- std::string BareMetal::computeSysRoot () const { return SysRoot; }
269
-
270
370
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
271
371
// Get multilibs in reverse order because they're ordered most-specific last.
272
372
if (!SelectedMultilibs.empty ())
@@ -294,10 +394,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
294
394
if (std::optional<std::string> Path = getStdlibIncludePath ())
295
395
addSystemInclude (DriverArgs, CC1Args, *Path);
296
396
297
- const SmallString<128 > SysRoot (computeSysRoot ());
298
- if (!SysRoot .empty ()) {
397
+ const SmallString<128 > SysRootDir (computeSysRoot ());
398
+ if (!SysRootDir .empty ()) {
299
399
for (const Multilib &M : getOrderedMultilibs ()) {
300
- SmallString<128 > Dir (SysRoot );
400
+ SmallString<128 > Dir (SysRootDir );
301
401
llvm::sys::path::append (Dir, M.includeSuffix ());
302
402
llvm::sys::path::append (Dir, " include" );
303
403
addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -311,6 +411,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
311
411
CC1Args.push_back (" -nostdsysteminc" );
312
412
}
313
413
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
+
314
427
void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
315
428
ArgStringList &CC1Args) const {
316
429
if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -341,23 +454,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
341
454
};
342
455
343
456
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 ;
353
466
}
354
467
355
- std::string SysRoot (computeSysRoot ());
356
- if (SysRoot .empty ())
468
+ std::string SysRootDir (computeSysRoot ());
469
+ if (SysRootDir .empty ())
357
470
return ;
358
471
359
472
for (const Multilib &M : getOrderedMultilibs ()) {
360
- SmallString<128 > Dir (SysRoot );
473
+ SmallString<128 > Dir (SysRootDir );
361
474
llvm::sys::path::append (Dir, M.gccSuffix ());
362
475
switch (GetCXXStdlibType (DriverArgs)) {
363
476
case ToolChain::CST_Libcxx: {
0 commit comments