@@ -31,6 +31,40 @@ using namespace clang::driver;
31
31
using namespace clang ::driver::tools;
32
32
using namespace clang ::driver::toolchains;
33
33
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
+
34
68
static bool findRISCVMultilibs (const Driver &D,
35
69
const llvm::Triple &TargetTriple,
36
70
const ArgList &Args, DetectedMultilibs &Result) {
@@ -95,7 +129,8 @@ static bool findRISCVMultilibs(const Driver &D,
95
129
return false ;
96
130
}
97
131
98
- static std::string computeBaseSysRoot (const Driver &D, bool IncludeTriple) {
132
+ static std::string computeClangRuntimesSysRoot (const Driver &D,
133
+ bool IncludeTriple) {
99
134
if (!D.SysRoot .empty ())
100
135
return D.SysRoot ;
101
136
@@ -108,56 +143,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) {
108
143
return std::string (SysRootDir);
109
144
}
110
145
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 ();
126
155
}
156
+ return false ;
127
157
}
128
158
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);
142
168
}
143
169
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 ;
147
189
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);
150
204
151
- if (Triple.getOS () != llvm::Triple::UnknownOS)
152
- return false ;
205
+ // Use the clang-runtimes path.
206
+ return computeClangRuntimesSysRoot (D, /* IncludeTriple*/ true );
207
+ }
153
208
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);
155
216
}
156
217
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
+ }
161
263
}
162
264
163
265
static void
@@ -216,7 +318,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple,
216
318
return {};
217
319
}
218
320
} else {
219
- MultilibPath = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
321
+ MultilibPath = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
220
322
llvm::sys::path::append (MultilibPath, MultilibFilename);
221
323
}
222
324
return MultilibPath;
@@ -234,15 +336,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
234
336
if (D.getVFS ().exists (*MultilibPath)) {
235
337
// If multilib.yaml is found, update sysroot so it doesn't use a target
236
338
// specific suffix
237
- SysRoot = computeBaseSysRoot (D, /* IncludeTriple=*/ false );
339
+ SysRoot = computeClangRuntimesSysRoot (D, /* IncludeTriple=*/ false );
238
340
SmallVector<StringRef> CustomFlagMacroDefines;
239
341
findMultilibsFromYAML (*this , D, *MultilibPath, Args, Result,
240
342
CustomFlagMacroDefines);
241
343
SelectedMultilibs = Result.SelectedMultilibs ;
242
344
Multilibs = Result.Multilibs ;
243
345
MultilibMacroDefines.append (CustomFlagMacroDefines.begin (),
244
346
CustomFlagMacroDefines.end ());
245
- } else if (isRISCVBareMetal (Triple)) {
347
+ } else if (isRISCVBareMetal (Triple) && ! detectGCCToolchainAdjacent (D) ) {
246
348
if (findRISCVMultilibs (D, Triple, Args, Result)) {
247
349
SelectedMultilibs = Result.SelectedMultilibs ;
248
350
Multilibs = Result.Multilibs ;
@@ -263,8 +365,6 @@ Tool *BareMetal::buildStaticLibTool() const {
263
365
return new tools::baremetal::StaticLibTool (*this );
264
366
}
265
367
266
- std::string BareMetal::computeSysRoot () const { return SysRoot; }
267
-
268
368
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs () const {
269
369
// Get multilibs in reverse order because they're ordered most-specific last.
270
370
if (!SelectedMultilibs.empty ())
@@ -292,10 +392,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
292
392
if (std::optional<std::string> Path = getStdlibIncludePath ())
293
393
addSystemInclude (DriverArgs, CC1Args, *Path);
294
394
295
- const SmallString<128 > SysRoot (computeSysRoot ());
296
- if (!SysRoot .empty ()) {
395
+ const SmallString<128 > SysRootDir (computeSysRoot ());
396
+ if (!SysRootDir .empty ()) {
297
397
for (const Multilib &M : getOrderedMultilibs ()) {
298
- SmallString<128 > Dir (SysRoot );
398
+ SmallString<128 > Dir (SysRootDir );
299
399
llvm::sys::path::append (Dir, M.includeSuffix ());
300
400
llvm::sys::path::append (Dir, " include" );
301
401
addSystemInclude (DriverArgs, CC1Args, Dir.str ());
@@ -309,6 +409,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs,
309
409
CC1Args.push_back (" -nostdsysteminc" );
310
410
}
311
411
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
+
312
425
void BareMetal::AddClangCXXStdlibIncludeArgs (const ArgList &DriverArgs,
313
426
ArgStringList &CC1Args) const {
314
427
if (DriverArgs.hasArg (options::OPT_nostdinc, options::OPT_nostdlibinc,
@@ -339,23 +452,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
339
452
};
340
453
341
454
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 ;
351
464
}
352
465
353
- std::string SysRoot (computeSysRoot ());
354
- if (SysRoot .empty ())
466
+ std::string SysRootDir (computeSysRoot ());
467
+ if (SysRootDir .empty ())
355
468
return ;
356
469
357
470
for (const Multilib &M : getOrderedMultilibs ()) {
358
- SmallString<128 > Dir (SysRoot );
471
+ SmallString<128 > Dir (SysRootDir );
359
472
llvm::sys::path::append (Dir, M.gccSuffix ());
360
473
switch (GetCXXStdlibType (DriverArgs)) {
361
474
case ToolChain::CST_Libcxx: {
0 commit comments