-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[Driver] Add support for GCC installation detection in Baremetal toolchain #121829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,6 +31,40 @@ using namespace clang::driver; | |
using namespace clang::driver::tools; | ||
using namespace clang::driver::toolchains; | ||
|
||
/// Is the triple {aarch64.aarch64_be}-none-elf? | ||
static bool isAArch64BareMetal(const llvm::Triple &Triple) { | ||
if (Triple.getArch() != llvm::Triple::aarch64 && | ||
Triple.getArch() != llvm::Triple::aarch64_be) | ||
return false; | ||
|
||
if (Triple.getVendor() != llvm::Triple::UnknownVendor) | ||
return false; | ||
|
||
if (Triple.getOS() != llvm::Triple::UnknownOS) | ||
return false; | ||
|
||
return Triple.getEnvironmentName() == "elf"; | ||
} | ||
|
||
static bool isRISCVBareMetal(const llvm::Triple &Triple) { | ||
if (!Triple.isRISCV()) | ||
return false; | ||
|
||
if (Triple.getVendor() != llvm::Triple::UnknownVendor) | ||
return false; | ||
|
||
if (Triple.getOS() != llvm::Triple::UnknownOS) | ||
return false; | ||
|
||
return Triple.getEnvironmentName() == "elf"; | ||
} | ||
|
||
/// Is the triple powerpc[64][le]-*-none-eabi? | ||
static bool isPPCBareMetal(const llvm::Triple &Triple) { | ||
return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && | ||
Triple.getEnvironment() == llvm::Triple::EABI; | ||
} | ||
|
||
static bool findRISCVMultilibs(const Driver &D, | ||
const llvm::Triple &TargetTriple, | ||
const ArgList &Args, DetectedMultilibs &Result) { | ||
|
@@ -95,7 +129,8 @@ static bool findRISCVMultilibs(const Driver &D, | |
return false; | ||
} | ||
|
||
static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) { | ||
static std::string computeClangRuntimesSysRoot(const Driver &D, | ||
bool IncludeTriple) { | ||
if (!D.SysRoot.empty()) | ||
return D.SysRoot; | ||
|
||
|
@@ -108,56 +143,123 @@ static std::string computeBaseSysRoot(const Driver &D, bool IncludeTriple) { | |
return std::string(SysRootDir); | ||
} | ||
|
||
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, | ||
const ArgList &Args) | ||
: ToolChain(D, Triple, Args), | ||
SysRoot(computeBaseSysRoot(D, /*IncludeTriple=*/true)) { | ||
getProgramPaths().push_back(getDriver().Dir); | ||
|
||
findMultilibs(D, Triple, Args); | ||
SmallString<128> SysRoot(computeSysRoot()); | ||
if (!SysRoot.empty()) { | ||
for (const Multilib &M : getOrderedMultilibs()) { | ||
SmallString<128> Dir(SysRoot); | ||
llvm::sys::path::append(Dir, M.osSuffix(), "lib"); | ||
getFilePaths().push_back(std::string(Dir)); | ||
getLibraryPaths().push_back(std::string(Dir)); | ||
} | ||
// Only consider the GCC toolchain based on the values provided through the | ||
// `--gcc-toolchain` and `--gcc-install-dir` flags. The function below returns | ||
// whether the GCC toolchain was initialized successfully. | ||
bool BareMetal::initGCCInstallation(const llvm::Triple &Triple, | ||
const llvm::opt::ArgList &Args) { | ||
if (Args.getLastArg(options::OPT_gcc_toolchain) || | ||
Args.getLastArg(clang::driver::options::OPT_gcc_install_dir_EQ)) { | ||
GCCInstallation.init(Triple, Args); | ||
return GCCInstallation.isValid(); | ||
} | ||
return false; | ||
} | ||
|
||
/// Is the triple {aarch64.aarch64_be}-none-elf? | ||
static bool isAArch64BareMetal(const llvm::Triple &Triple) { | ||
if (Triple.getArch() != llvm::Triple::aarch64 && | ||
Triple.getArch() != llvm::Triple::aarch64_be) | ||
return false; | ||
|
||
if (Triple.getVendor() != llvm::Triple::UnknownVendor) | ||
return false; | ||
|
||
if (Triple.getOS() != llvm::Triple::UnknownOS) | ||
return false; | ||
|
||
return Triple.getEnvironmentName() == "elf"; | ||
// This logic is adapted from RISCVToolChain.cpp as part of the ongoing effort | ||
// to merge RISCVToolChain into the Baremetal toolchain. It infers the presence | ||
// of a valid GCC toolchain by checking whether the `crt0.o` file exists in the | ||
// `bin/../<target-triple>/lib` directory. | ||
static bool detectGCCToolchainAdjacent(const Driver &D) { | ||
SmallString<128> GCCDir; | ||
llvm::sys::path::append(GCCDir, D.Dir, "..", D.getTargetTriple(), | ||
"lib/crt0.o"); | ||
return llvm::sys::fs::exists(GCCDir); | ||
} | ||
|
||
static bool isRISCVBareMetal(const llvm::Triple &Triple) { | ||
if (!Triple.isRISCV()) | ||
return false; | ||
// If no sysroot is provided the driver will first attempt to infer it from the | ||
// values of `--gcc-install-dir` or `--gcc-toolchain`, which specify the | ||
// location of a GCC toolchain. | ||
// If neither flag is used, the sysroot defaults to either: | ||
// - `bin/../<target-triple>` | ||
// - `bin/../lib/clang-runtimes/<target-triple>` | ||
// | ||
// To use the `clang-runtimes` path, ensure that `../<target-triple>/lib/crt0.o` | ||
// does not exist relative to the driver. | ||
std::string BareMetal::computeSysRoot() const { | ||
// Use Baremetal::sysroot if it has already been set. | ||
if (!SysRoot.empty()) | ||
return SysRoot; | ||
|
||
// Use the sysroot specified via the `--sysroot` command-line flag, if | ||
// provided. | ||
const Driver &D = getDriver(); | ||
if (!D.SysRoot.empty()) | ||
return D.SysRoot; | ||
|
||
if (Triple.getVendor() != llvm::Triple::UnknownVendor) | ||
return false; | ||
// Attempt to infer sysroot from a valid GCC installation. | ||
// If no valid GCC installation, check for a GCC toolchain alongside Clang. | ||
SmallString<128> inferredSysRoot; | ||
if (IsGCCInstallationValid) { | ||
llvm::sys::path::append(inferredSysRoot, GCCInstallation.getParentLibPath(), | ||
"..", GCCInstallation.getTriple().str()); | ||
} else if (detectGCCToolchainAdjacent(D)) { | ||
// Use the triple as provided to the driver. Unlike the parsed triple | ||
// this has not been normalized to always contain every field. | ||
llvm::sys::path::append(inferredSysRoot, D.Dir, "..", D.getTargetTriple()); | ||
} | ||
// If a valid sysroot was inferred and exists, use it | ||
if (!inferredSysRoot.empty() && llvm::sys::fs::exists(inferredSysRoot)) | ||
return std::string(inferredSysRoot); | ||
|
||
if (Triple.getOS() != llvm::Triple::UnknownOS) | ||
return false; | ||
// Use the clang-runtimes path. | ||
return computeClangRuntimesSysRoot(D, /*IncludeTriple*/ true); | ||
} | ||
|
||
return Triple.getEnvironmentName() == "elf"; | ||
static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, | ||
const Multilib &Multilib, | ||
StringRef InstallPath, | ||
ToolChain::path_list &Paths) { | ||
if (const auto &PathsCallback = Multilibs.filePathsCallback()) | ||
for (const auto &Path : PathsCallback(Multilib)) | ||
addPathIfExists(D, InstallPath + Path, Paths); | ||
} | ||
|
||
/// Is the triple powerpc[64][le]-*-none-eabi? | ||
static bool isPPCBareMetal(const llvm::Triple &Triple) { | ||
return Triple.isPPC() && Triple.getOS() == llvm::Triple::UnknownOS && | ||
Triple.getEnvironment() == llvm::Triple::EABI; | ||
// GCC mutltilibs will only work for those targets that have their multlib | ||
// structure encoded into GCCInstallation. Baremetal toolchain supports ARM, | ||
// AArch64, RISCV and PPC and of these only RISCV have GCC multilibs hardcoded | ||
// in GCCInstallation. | ||
BareMetal::BareMetal(const Driver &D, const llvm::Triple &Triple, | ||
const ArgList &Args) | ||
: Generic_ELF(D, Triple, Args) { | ||
IsGCCInstallationValid = initGCCInstallation(Triple, Args); | ||
std::string ComputedSysRoot = computeSysRoot(); | ||
if (IsGCCInstallationValid) { | ||
if (!isRISCVBareMetal(Triple)) | ||
D.Diag(clang::diag::warn_drv_multilib_not_available_for_target); | ||
|
||
Multilibs = GCCInstallation.getMultilibs(); | ||
SelectedMultilibs.assign({GCCInstallation.getMultilib()}); | ||
|
||
path_list &Paths = getFilePaths(); | ||
// Add toolchain/multilib specific file paths. | ||
addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(), | ||
GCCInstallation.getInstallPath(), Paths); | ||
// Adding filepath for locating crt{begin,end}.o files. | ||
Paths.push_back(GCCInstallation.getInstallPath().str()); | ||
// Adding filepath for locating crt0.o file. | ||
Paths.push_back(ComputedSysRoot + "/lib"); | ||
|
||
ToolChain::path_list &PPaths = getProgramPaths(); | ||
// Multilib cross-compiler GCC installations put ld in a triple-prefixed | ||
// directory off of the parent of the GCC installation. | ||
PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + | ||
GCCInstallation.getTriple().str() + "/bin") | ||
.str()); | ||
PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str()); | ||
} else { | ||
smithp35 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
getProgramPaths().push_back(getDriver().Dir); | ||
findMultilibs(D, Triple, Args); | ||
const SmallString<128> SysRootDir(computeSysRoot()); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assuming it is still the ToolChain::SysRoot that is set on line 208 can you still use it rather than recompute. All computeSysRoot will do is return ToolChain::SysRoot as it has been set either on line 208 or by findMultilibs? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed!. I didn't do it previously to minimize code changes. |
||
if (!SysRootDir.empty()) { | ||
for (const Multilib &M : getOrderedMultilibs()) { | ||
SmallString<128> Dir(SysRootDir); | ||
llvm::sys::path::append(Dir, M.osSuffix(), "lib"); | ||
getFilePaths().push_back(std::string(Dir)); | ||
getLibraryPaths().push_back(std::string(Dir)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
static void | ||
|
@@ -216,7 +318,7 @@ getMultilibConfigPath(const Driver &D, const llvm::Triple &Triple, | |
return {}; | ||
} | ||
} else { | ||
MultilibPath = computeBaseSysRoot(D, /*IncludeTriple=*/false); | ||
MultilibPath = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false); | ||
llvm::sys::path::append(MultilibPath, MultilibFilename); | ||
} | ||
return MultilibPath; | ||
|
@@ -234,15 +336,15 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple, | |
if (D.getVFS().exists(*MultilibPath)) { | ||
// If multilib.yaml is found, update sysroot so it doesn't use a target | ||
// specific suffix | ||
SysRoot = computeBaseSysRoot(D, /*IncludeTriple=*/false); | ||
SysRoot = computeClangRuntimesSysRoot(D, /*IncludeTriple=*/false); | ||
SmallVector<StringRef> CustomFlagMacroDefines; | ||
findMultilibsFromYAML(*this, D, *MultilibPath, Args, Result, | ||
CustomFlagMacroDefines); | ||
SelectedMultilibs = Result.SelectedMultilibs; | ||
Multilibs = Result.Multilibs; | ||
MultilibMacroDefines.append(CustomFlagMacroDefines.begin(), | ||
CustomFlagMacroDefines.end()); | ||
} else if (isRISCVBareMetal(Triple)) { | ||
} else if (isRISCVBareMetal(Triple) && !detectGCCToolchainAdjacent(D)) { | ||
if (findRISCVMultilibs(D, Triple, Args, Result)) { | ||
SelectedMultilibs = Result.SelectedMultilibs; | ||
Multilibs = Result.Multilibs; | ||
|
@@ -263,8 +365,6 @@ Tool *BareMetal::buildStaticLibTool() const { | |
return new tools::baremetal::StaticLibTool(*this); | ||
} | ||
|
||
std::string BareMetal::computeSysRoot() const { return SysRoot; } | ||
|
||
BareMetal::OrderedMultilibs BareMetal::getOrderedMultilibs() const { | ||
// Get multilibs in reverse order because they're ordered most-specific last. | ||
if (!SelectedMultilibs.empty()) | ||
|
@@ -292,10 +392,10 @@ void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs, | |
if (std::optional<std::string> Path = getStdlibIncludePath()) | ||
addSystemInclude(DriverArgs, CC1Args, *Path); | ||
|
||
const SmallString<128> SysRoot(computeSysRoot()); | ||
if (!SysRoot.empty()) { | ||
const SmallString<128> SysRootDir(computeSysRoot()); | ||
if (!SysRootDir.empty()) { | ||
for (const Multilib &M : getOrderedMultilibs()) { | ||
SmallString<128> Dir(SysRoot); | ||
SmallString<128> Dir(SysRootDir); | ||
llvm::sys::path::append(Dir, M.includeSuffix()); | ||
llvm::sys::path::append(Dir, "include"); | ||
addSystemInclude(DriverArgs, CC1Args, Dir.str()); | ||
|
@@ -309,6 +409,19 @@ void BareMetal::addClangTargetOptions(const ArgList &DriverArgs, | |
CC1Args.push_back("-nostdsysteminc"); | ||
} | ||
|
||
void BareMetal::addLibStdCxxIncludePaths( | ||
const llvm::opt::ArgList &DriverArgs, | ||
llvm::opt::ArgStringList &CC1Args) const { | ||
if (!IsGCCInstallationValid) | ||
return; | ||
const GCCVersion &Version = GCCInstallation.getVersion(); | ||
StringRef TripleStr = GCCInstallation.getTriple().str(); | ||
const Multilib &Multilib = GCCInstallation.getMultilib(); | ||
addLibStdCXXIncludePaths(computeSysRoot() + "/include/c++/" + Version.Text, | ||
TripleStr, Multilib.includeSuffix(), DriverArgs, | ||
CC1Args); | ||
} | ||
|
||
void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, | ||
ArgStringList &CC1Args) const { | ||
if (DriverArgs.hasArg(options::OPT_nostdinc, options::OPT_nostdlibinc, | ||
|
@@ -339,23 +452,23 @@ void BareMetal::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, | |
}; | ||
|
||
switch (GetCXXStdlibType(DriverArgs)) { | ||
case ToolChain::CST_Libcxx: { | ||
SmallString<128> P(D.Dir); | ||
llvm::sys::path::append(P, "..", "include"); | ||
AddCXXIncludePath(P); | ||
break; | ||
} | ||
case ToolChain::CST_Libstdcxx: | ||
// We only support libc++ toolchain installation. | ||
break; | ||
case ToolChain::CST_Libcxx: { | ||
SmallString<128> P(D.Dir); | ||
llvm::sys::path::append(P, "..", "include"); | ||
AddCXXIncludePath(P); | ||
break; | ||
} | ||
case ToolChain::CST_Libstdcxx: | ||
addLibStdCxxIncludePaths(DriverArgs, CC1Args); | ||
break; | ||
} | ||
|
||
std::string SysRoot(computeSysRoot()); | ||
if (SysRoot.empty()) | ||
std::string SysRootDir(computeSysRoot()); | ||
if (SysRootDir.empty()) | ||
return; | ||
|
||
for (const Multilib &M : getOrderedMultilibs()) { | ||
SmallString<128> Dir(SysRoot); | ||
SmallString<128> Dir(SysRootDir); | ||
llvm::sys::path::append(Dir, M.gccSuffix()); | ||
switch (GetCXXStdlibType(DriverArgs)) { | ||
case ToolChain::CST_Libcxx: { | ||
|
Uh oh!
There was an error while loading. Please reload this page.