blob: 701886e47d66237edd4f24c776290167d9ec5eb3 [file] [log] [blame]
//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Gnu.h"
#include "Arch/ARM.h"
#include "Arch/CSKY.h"
#include "Arch/Mips.h"
#include "Arch/PPC.h"
#include "Arch/RISCV.h"
#include "Arch/Sparc.h"
#include "Arch/SystemZ.h"
#include "CommonArgs.h"
#include "Linux.h"
#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/Tool.h"
#include "clang/Driver/ToolChain.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/TargetParser.h"
#include "llvm/Support/VirtualFileSystem.h"
#include <system_error>
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
using tools::addMultilibFlag;
using tools::addPathIfExists;
static bool forwardToGCC(const Option &O) {
// LinkerInput options have been forwarded. Don't duplicate.
if (O.hasFlag(options::LinkerInput))
return false;
return O.matches(options::OPT_Link_Group) || O.hasFlag(options::LinkOption);
}
// Switch CPU names not recognized by GNU assembler to a close CPU that it does
// recognize, instead of a lower march from being picked in the absence of a cpu
// flag.
static void normalizeCPUNamesForAssembler(const ArgList &Args,
ArgStringList &CmdArgs) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef CPUArg(A->getValue());
if (CPUArg.equals_insensitive("krait"))
CmdArgs.push_back("-mcpu=cortex-a15");
else if (CPUArg.equals_insensitive("kryo"))
CmdArgs.push_back("-mcpu=cortex-a57");
else
Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
}
}
void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
ArgStringList CmdArgs;
for (const auto &A : Args) {
if (forwardToGCC(A->getOption())) {
// It is unfortunate that we have to claim here, as this means
// we will basically never report anything interesting for
// platforms using a generic gcc, even if we are just using gcc
// to get to the assembler.
A->claim();
A->render(Args, CmdArgs);
}
}
RenderExtraToolArgs(JA, CmdArgs);
// If using a driver driver, force the arch.
if (getToolChain().getTriple().isOSDarwin()) {
CmdArgs.push_back("-arch");
CmdArgs.push_back(
Args.MakeArgString(getToolChain().getDefaultUniversalArchName()));
}
// Try to force gcc to match the tool chain we want, if we recognize
// the arch.
//
// FIXME: The triple class should directly provide the information we want
// here.
switch (getToolChain().getArch()) {
default:
break;
case llvm::Triple::x86:
case llvm::Triple::ppc:
case llvm::Triple::ppcle:
CmdArgs.push_back("-m32");
break;
case llvm::Triple::x86_64:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
CmdArgs.push_back("-m64");
break;
case llvm::Triple::sparcel:
CmdArgs.push_back("-EL");
break;
}
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Unexpected output");
CmdArgs.push_back("-fsyntax-only");
}
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
// Only pass -x if gcc will understand it; otherwise hope gcc
// understands the suffix correctly. The main use case this would go
// wrong in is for linker inputs if they happened to have an odd
// suffix; really the only way to get this to happen is a command
// like '-x foobar a.c' which will treat a.c like a linker input.
//
// FIXME: For the linker case specifically, can we safely convert
// inputs into '-Wl,' options?
for (const auto &II : Inputs) {
// Don't try to pass LLVM or AST inputs to a generic gcc.
if (types::isLLVMIR(II.getType()))
D.Diag(clang::diag::err_drv_no_linker_llvm_support)
<< getToolChain().getTripleString();
else if (II.getType() == types::TY_AST)
D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString();
else if (II.getType() == types::TY_ModuleFile)
D.Diag(diag::err_drv_no_module_support)
<< getToolChain().getTripleString();
if (types::canTypeBeUserSpecified(II.getType())) {
CmdArgs.push_back("-x");
CmdArgs.push_back(types::getTypeName(II.getType()));
}
if (II.isFilename())
CmdArgs.push_back(II.getFilename());
else {
const Arg &A = II.getInputArg();
// Reverse translate some rewritten options.
if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) {
CmdArgs.push_back("-lstdc++");
continue;
}
// Don't render as input, we need gcc to do the translations.
A.render(Args, CmdArgs);
}
}
const std::string &customGCCName = D.getCCCGenericGCCName();
const char *GCCName;
if (!customGCCName.empty())
GCCName = customGCCName.c_str();
else if (D.CCCIsCXX()) {
GCCName = "g++";
} else
GCCName = "gcc";
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}
void tools::gcc::Preprocessor::RenderExtraToolArgs(
const JobAction &JA, ArgStringList &CmdArgs) const {
CmdArgs.push_back("-E");
}
void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
switch (JA.getType()) {
// If -flto, etc. are present then make sure not to force assembly output.
case types::TY_LLVM_IR:
case types::TY_LTO_IR:
case types::TY_LLVM_BC:
case types::TY_LTO_BC:
CmdArgs.push_back("-c");
break;
// We assume we've got an "integrated" assembler in that gcc will produce an
// object file itself.
case types::TY_Object:
CmdArgs.push_back("-c");
break;
case types::TY_PP_Asm:
CmdArgs.push_back("-S");
break;
case types::TY_Nothing:
CmdArgs.push_back("-fsyntax-only");
break;
default:
D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType());
}
}
void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA,
ArgStringList &CmdArgs) const {
// The types are (hopefully) good enough.
}
// On Arm the endianness of the output file is determined by the target and
// can be overridden by the pseudo-target flags '-mlittle-endian'/'-EL' and
// '-mbig-endian'/'-EB'. Unlike other targets the flag does not result in a
// normalized triple so we must handle the flag here.
static bool isArmBigEndian(const llvm::Triple &Triple,
const ArgList &Args) {
bool IsBigEndian = false;
switch (Triple.getArch()) {
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
IsBigEndian = true;
[[fallthrough]];
case llvm::Triple::arm:
case llvm::Triple::thumb:
if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
options::OPT_mbig_endian))
IsBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
break;
default:
break;
}
return IsBigEndian;
}
static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
switch (T.getArch()) {
case llvm::Triple::x86:
if (T.isOSIAMCU())
return "elf_iamcu";
return "elf_i386";
case llvm::Triple::aarch64:
return "aarch64linux";
case llvm::Triple::aarch64_be:
return "aarch64linuxb";
case llvm::Triple::arm:
case llvm::Triple::thumb:
case llvm::Triple::armeb:
case llvm::Triple::thumbeb:
return isArmBigEndian(T, Args) ? "armelfb_linux_eabi" : "armelf_linux_eabi";
case llvm::Triple::m68k:
return "m68kelf";
case llvm::Triple::ppc:
if (T.isOSLinux())
return "elf32ppclinux";
return "elf32ppc";
case llvm::Triple::ppcle:
if (T.isOSLinux())
return "elf32lppclinux";
return "elf32lppc";
case llvm::Triple::ppc64:
return "elf64ppc";
case llvm::Triple::ppc64le:
return "elf64lppc";
case llvm::Triple::riscv32:
return "elf32lriscv";
case llvm::Triple::riscv64:
return "elf64lriscv";
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
return "elf32_sparc";
case llvm::Triple::sparcv9:
return "elf64_sparc";
case llvm::Triple::mips:
return "elf32btsmip";
case llvm::Triple::mipsel:
return "elf32ltsmip";
case llvm::Triple::mips64:
if (tools::mips::hasMipsAbiArg(Args, "n32") ||
T.getEnvironment() == llvm::Triple::GNUABIN32)
return "elf32btsmipn32";
return "elf64btsmip";
case llvm::Triple::mips64el:
if (tools::mips::hasMipsAbiArg(Args, "n32") ||
T.getEnvironment() == llvm::Triple::GNUABIN32)
return "elf32ltsmipn32";
return "elf64ltsmip";
case llvm::Triple::systemz:
return "elf64_s390";
case llvm::Triple::x86_64:
if (T.isX32())
return "elf32_x86_64";
return "elf_x86_64";
case llvm::Triple::ve:
return "elf64ve";
case llvm::Triple::csky:
return "cskyelf_linux";
default:
return nullptr;
}
}
static bool getPIE(const ArgList &Args, const ToolChain &TC) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie))
return false;
Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
options::OPT_nopie);
if (!A)
return TC.isPIEDefault(Args);
return A->getOption().matches(options::OPT_pie);
}
static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) {
bool HasStaticPIE = Args.hasArg(options::OPT_static_pie);
// -no-pie is an alias for -nopie. So, handling -nopie takes care of
// -no-pie as well.
if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) {
const Driver &D = TC.getDriver();
const llvm::opt::OptTable &Opts = D.getOpts();
const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
const char *NoPIEName = Opts.getOptionName(options::OPT_nopie);
D.Diag(diag::err_drv_cannot_mix_options) << StaticPIEName << NoPIEName;
}
return HasStaticPIE;
}
static bool getStatic(const ArgList &Args) {
return Args.hasArg(options::OPT_static) &&
!Args.hasArg(options::OPT_static_pie);
}
void tools::gnutools::StaticLibTool::ConstructJob(
Compilation &C, const JobAction &JA, const InputInfo &Output,
const InputInfoList &Inputs, const ArgList &Args,
const char *LinkingOutput) const {
const Driver &D = getToolChain().getDriver();
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
// ar tool command "llvm-ar <options> <output_file> <input_files>".
ArgStringList CmdArgs;
// Create and insert file members with a deterministic index.
CmdArgs.push_back("rcsD");
CmdArgs.push_back(Output.getFilename());
for (const auto &II : Inputs) {
if (II.isFilename()) {
CmdArgs.push_back(II.getFilename());
}
}
// Delete old output archive file if it already exists before generating a new
// archive file.
auto OutputFileName = Output.getFilename();
if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
return;
}
}
const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}
void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
// FIXME: The Linker class constructor takes a ToolChain and not a
// Generic_ELF, so the static_cast might return a reference to a invalid
// instance (see PR45061). Ideally, the Linker constructor needs to take a
// Generic_ELF instead.
const toolchains::Generic_ELF &ToolChain =
static_cast<const toolchains::Generic_ELF &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool isAndroid = ToolChain.getTriple().isAndroid();
const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU();
const bool IsVE = ToolChain.getTriple().isVE();
const bool IsPIE = getPIE(Args, ToolChain);
const bool IsStaticPIE = getStaticPIE(Args, ToolChain);
const bool IsStatic = getStatic(Args);
const bool HasCRTBeginEndFiles =
ToolChain.getTriple().hasEnvironment() ||
(ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies);
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
if (IsPIE)
CmdArgs.push_back("-pie");
if (IsStaticPIE) {
CmdArgs.push_back("-static");
CmdArgs.push_back("-pie");
CmdArgs.push_back("--no-dynamic-linker");
CmdArgs.push_back("-z");
CmdArgs.push_back("text");
}
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_s))
CmdArgs.push_back("-s");
if (Triple.isARM() || Triple.isThumb() || Triple.isAArch64()) {
bool IsBigEndian = isArmBigEndian(Triple, Args);
if (IsBigEndian)
arm::appendBE8LinkFlag(Args, CmdArgs, Triple);
IsBigEndian = IsBigEndian || Arch == llvm::Triple::aarch64_be;
CmdArgs.push_back(IsBigEndian ? "-EB" : "-EL");
}
// Most Android ARM64 targets should enable the linker fix for erratum
// 843419. Only non-Cortex-A53 devices are allowed to skip this flag.
if (Arch == llvm::Triple::aarch64 && isAndroid) {
std::string CPU = getCPUName(D, Args, Triple);
if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
CmdArgs.push_back("--fix-cortex-a53-843419");
}
ToolChain.addExtraOpts(CmdArgs);
CmdArgs.push_back("--eh-frame-hdr");
if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) {
CmdArgs.push_back("-m");
CmdArgs.push_back(LDMOption);
} else {
D.Diag(diag::err_target_unknown_triple) << Triple.str();
return;
}
if (Triple.isRISCV())
CmdArgs.push_back("-X");
if (Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-shared");
if (IsStatic) {
CmdArgs.push_back("-static");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE &&
!Args.hasArg(options::OPT_r)) {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) +
ToolChain.getDynamicLinker(Args)));
}
}
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles,
options::OPT_r)) {
if (!isAndroid && !IsIAMCU) {
const char *crt1 = nullptr;
if (!Args.hasArg(options::OPT_shared)) {
if (Args.hasArg(options::OPT_pg))
crt1 = "gcrt1.o";
else if (IsPIE)
crt1 = "Scrt1.o";
else if (IsStaticPIE)
crt1 = "rcrt1.o";
else
crt1 = "crt1.o";
}
if (crt1)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
}
if (IsVE) {
CmdArgs.push_back("-z");
CmdArgs.push_back("max-page-size=0x4000000");
}
if (IsIAMCU)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
else if (HasCRTBeginEndFiles) {
std::string P;
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT &&
!isAndroid) {
std::string crtbegin = ToolChain.getCompilerRT(Args, "crtbegin",
ToolChain::FT_Object);
if (ToolChain.getVFS().exists(crtbegin))
P = crtbegin;
}
if (P.empty()) {
const char *crtbegin;
if (Args.hasArg(options::OPT_shared))
crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
else if (IsStatic)
crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
else if (IsPIE || IsStaticPIE)
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
else
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
P = ToolChain.GetFilePath(crtbegin);
}
CmdArgs.push_back(Args.MakeArgString(P));
}
// Add crtfastmath.o if available and fast math is enabled.
ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
Args.AddAllArgs(CmdArgs, options::OPT_u);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
D.getLTOMode() == LTOK_Thin);
}
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
CmdArgs.push_back("--no-demangle");
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
addLinkerCompressDebugSectionsOption(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
addHIPRuntimeLibArgs(ToolChain, Args, CmdArgs);
// The profile runtime also needs access to system libraries.
getToolChain().addProfileRTLibs(Args, CmdArgs);
if (D.CCCIsCXX() &&
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs,
options::OPT_r)) {
if (ToolChain.ShouldLinkCXXStdlib(Args)) {
bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) &&
!Args.hasArg(options::OPT_static);
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bstatic");
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (OnlyLibstdcxxStatic)
CmdArgs.push_back("-Bdynamic");
}
CmdArgs.push_back("-lm");
}
// If we are linking for the device all symbols should be bound locally. The
// symbols are already protected which makes this redundant. This is only
// necessary to work around a problem in bfd.
// TODO: Remove this once 'lld' becomes the only linker for offloading.
if (JA.isDeviceOffloading(Action::OFK_OpenMP))
CmdArgs.push_back("-Bsymbolic");
// Silence warnings when linking C code with a C++ '-stdlib' argument.
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
// Additional linker set-up and flags for Fortran. This is required in order
// to generate executables. As Fortran runtime depends on the C runtime,
// these dependencies need to be listed before the C runtime below (i.e.
// AddRuntTimeLibs).
if (D.IsFlangMode()) {
addFortranRuntimeLibraryPath(ToolChain, Args, CmdArgs);
addFortranRuntimeLibs(ToolChain, CmdArgs);
CmdArgs.push_back("-lm");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_r)) {
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
if (IsStatic || IsStaticPIE)
CmdArgs.push_back("--start-group");
if (NeedsSanitizerDeps)
linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
if (NeedsXRayDeps)
linkXRayRuntimeDeps(ToolChain, CmdArgs);
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
Args.hasArg(options::OPT_pthreads);
// Use the static OpenMP runtime with -static-openmp
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
!Args.hasArg(options::OPT_static);
// FIXME: Only pass GompNeedsRT = true for platforms with libgomp that
// require librt. Most modern Linux platforms do, but some may not.
if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP,
JA.isHostOffloading(Action::OFK_OpenMP),
/* GompNeedsRT= */ true))
// OpenMP runtimes implies pthreads when using the GNU toolchain.
// FIXME: Does this really make sense for all GNU toolchains?
WantPthread = true;
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
// LLVM support for atomics on 32-bit SPARC V8+ is incomplete, so
// forcibly link with libatomic as a workaround.
// TODO: Issue #41880 and D118021.
if (getToolChain().getTriple().getArch() == llvm::Triple::sparc) {
CmdArgs.push_back("--push-state");
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-latomic");
CmdArgs.push_back("--pop-state");
}
if (WantPthread && !isAndroid)
CmdArgs.push_back("-lpthread");
if (Args.hasArg(options::OPT_fsplit_stack))
CmdArgs.push_back("--wrap=pthread_create");
if (!Args.hasArg(options::OPT_nolibc))
CmdArgs.push_back("-lc");
// Add IAMCU specific libs, if needed.
if (IsIAMCU)
CmdArgs.push_back("-lgloss");
if (IsStatic || IsStaticPIE)
CmdArgs.push_back("--end-group");
else
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
// Add IAMCU specific libs (outside the group), if needed.
if (IsIAMCU) {
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lsoftfp");
CmdArgs.push_back("--no-as-needed");
}
}
if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) {
if (HasCRTBeginEndFiles) {
std::string P;
if (ToolChain.GetRuntimeLibType(Args) == ToolChain::RLT_CompilerRT &&
!isAndroid) {
std::string crtend = ToolChain.getCompilerRT(Args, "crtend",
ToolChain::FT_Object);
if (ToolChain.getVFS().exists(crtend))
P = crtend;
}
if (P.empty()) {
const char *crtend;
if (Args.hasArg(options::OPT_shared))
crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
else if (IsPIE || IsStaticPIE)
crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
else
crtend = isAndroid ? "crtend_android.o" : "crtend.o";
P = ToolChain.GetFilePath(crtend);
}
CmdArgs.push_back(Args.MakeArgString(P));
}
if (!isAndroid)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
}
Args.AddAllArgs(CmdArgs, options::OPT_T);
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
}
void tools::gnutools::Assembler::ConstructJob(Compilation &C,
const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const auto &D = getToolChain().getDriver();
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
const char *DefaultAssembler = "as";
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
if (const Arg *A = Args.getLastArg(options::OPT_gz, options::OPT_gz_EQ)) {
if (A->getOption().getID() == options::OPT_gz) {
CmdArgs.push_back("--compress-debug-sections");
} else {
StringRef Value = A->getValue();
if (Value == "none" || Value == "zlib") {
CmdArgs.push_back(
Args.MakeArgString("--compress-debug-sections=" + Twine(Value)));
} else {
D.Diag(diag::err_drv_unsupported_option_argument)
<< A->getOption().getName() << Value;
}
}
}
switch (getToolChain().getArch()) {
default:
break;
// Add --32/--64 to make sure we get the format we want.
// This is incomplete
case llvm::Triple::x86:
CmdArgs.push_back("--32");
break;
case llvm::Triple::x86_64:
if (getToolChain().getTriple().isX32())
CmdArgs.push_back("--x32");
else
CmdArgs.push_back("--64");
break;
case llvm::Triple::ppc: {
CmdArgs.push_back("-a32");
CmdArgs.push_back("-mppc");
CmdArgs.push_back("-mbig-endian");
CmdArgs.push_back(ppc::getPPCAsmModeForCPU(
getCPUName(D, Args, getToolChain().getTriple())));
break;
}
case llvm::Triple::ppcle: {
CmdArgs.push_back("-a32");
CmdArgs.push_back("-mppc");
CmdArgs.push_back("-mlittle-endian");
CmdArgs.push_back(ppc::getPPCAsmModeForCPU(
getCPUName(D, Args, getToolChain().getTriple())));
break;
}
case llvm::Triple::ppc64: {
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-mbig-endian");
CmdArgs.push_back(ppc::getPPCAsmModeForCPU(
getCPUName(D, Args, getToolChain().getTriple())));
break;
}
case llvm::Triple::ppc64le: {
CmdArgs.push_back("-a64");
CmdArgs.push_back("-mppc64");
CmdArgs.push_back("-mlittle-endian");
CmdArgs.push_back(ppc::getPPCAsmModeForCPU(
getCPUName(D, Args, getToolChain().getTriple())));
break;
}
case llvm::Triple::riscv32:
case llvm::Triple::riscv64: {
StringRef ABIName = riscv::getRISCVABI(Args, getToolChain().getTriple());
CmdArgs.push_back("-mabi");
CmdArgs.push_back(ABIName.data());
StringRef MArchName = riscv::getRISCVArch(Args, getToolChain().getTriple());
CmdArgs.push_back("-march");
CmdArgs.push_back(MArchName.data());
if (!Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))
Args.addOptOutFlag(CmdArgs, options::OPT_mrelax, options::OPT_mno_relax);
break;
}
case llvm::Triple::sparc:
case llvm::Triple::sparcel: {
CmdArgs.push_back("-32");
std::string CPU = getCPUName(D, Args, getToolChain().getTriple());
CmdArgs.push_back(
sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
case llvm::Triple::sparcv9: {
CmdArgs.push_back("-64");
std::string CPU = getCPUName(D, Args, getToolChain().getTriple());
CmdArgs.push_back(
sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb: {
const llvm::Triple &Triple2 = getToolChain().getTriple();
CmdArgs.push_back(isArmBigEndian(Triple2, Args) ? "-EB" : "-EL");
switch (Triple2.getSubArch()) {
case llvm::Triple::ARMSubArch_v7:
CmdArgs.push_back("-mfpu=neon");
break;
case llvm::Triple::ARMSubArch_v8:
CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8");
break;
default:
break;
}
switch (arm::getARMFloatABI(getToolChain(), Args)) {
case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!");
case arm::FloatABI::Soft:
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft"));
break;
case arm::FloatABI::SoftFP:
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp"));
break;
case arm::FloatABI::Hard:
CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard"));
break;
}
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
normalizeCPUNamesForAssembler(Args, CmdArgs);
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
break;
}
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be: {
CmdArgs.push_back(
getToolChain().getArch() == llvm::Triple::aarch64_be ? "-EB" : "-EL");
Args.AddLastArg(CmdArgs, options::OPT_march_EQ);
normalizeCPUNamesForAssembler(Args, CmdArgs);
break;
}
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName);
ABIName = mips::getGnuCompatibleMipsABIName(ABIName);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
CmdArgs.push_back("-mabi");
CmdArgs.push_back(ABIName.data());
// -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE,
// or -mshared (not implemented) is in effect.
if (RelocationModel == llvm::Reloc::Static)
CmdArgs.push_back("-mno-shared");
// LLVM doesn't support -mplt yet and acts as if it is always given.
// However, -mplt has no effect with the N64 ABI.
if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls))
CmdArgs.push_back("-call_nonpic");
if (getToolChain().getTriple().isLittleEndian())
CmdArgs.push_back("-EL");
else
CmdArgs.push_back("-EB");
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
if (StringRef(A->getValue()) == "2008")
CmdArgs.push_back(Args.MakeArgString("-mnan=2008"));
}
// Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default.
if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
options::OPT_mfp64)) {
A->claim();
A->render(Args, CmdArgs);
} else if (mips::shouldUseFPXX(
Args, getToolChain().getTriple(), CPUName, ABIName,
mips::getMipsFloatABI(getToolChain().getDriver(), Args,
getToolChain().getTriple())))
CmdArgs.push_back("-mfpxx");
// Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of
// -mno-mips16 is actually -no-mips16.
if (Arg *A =
Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) {
if (A->getOption().matches(options::OPT_mips16)) {
A->claim();
A->render(Args, CmdArgs);
} else {
A->claim();
CmdArgs.push_back("-no-mips16");
}
}
Args.AddLastArg(CmdArgs, options::OPT_mmicromips,
options::OPT_mno_micromips);
Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp);
Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2);
if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) {
// Do not use AddLastArg because not all versions of MIPS assembler
// support -mmsa / -mno-msa options.
if (A->getOption().matches(options::OPT_mmsa))
CmdArgs.push_back(Args.MakeArgString("-mmsa"));
}
Args.AddLastArg(CmdArgs, options::OPT_mhard_float,
options::OPT_msoft_float);
Args.AddLastArg(CmdArgs, options::OPT_mdouble_float,
options::OPT_msingle_float);
Args.AddLastArg(CmdArgs, options::OPT_modd_spreg,
options::OPT_mno_odd_spreg);
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
case llvm::Triple::systemz: {
// Always pass an -march option, since our default of z10 is later
// than the GNU assembler's default.
std::string CPUName = systemz::getSystemZTargetCPU(Args);
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
break;
}
case llvm::Triple::ve:
DefaultAssembler = "nas";
}
for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
options::OPT_fdebug_prefix_map_EQ)) {
StringRef Map = A->getValue();
if (!Map.contains('='))
D.Diag(diag::err_drv_invalid_argument_to_option)
<< Map << A->getOption().getName();
else {
CmdArgs.push_back(Args.MakeArgString("--debug-prefix-map"));
CmdArgs.push_back(Args.MakeArgString(Map));
}
A->claim();
}
Args.AddAllArgs(CmdArgs, options::OPT_I);
Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler);
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
const char *Exec =
Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler));
C.addCommand(std::make_unique<Command>(JA, *this,
ResponseFileSupport::AtFileCurCP(),
Exec, CmdArgs, Inputs, Output));
// Handle the debug info splitting at object creation time if we're
// creating an object.
// TODO: Currently only works on linux with newer objcopy.
if (Args.hasArg(options::OPT_gsplit_dwarf) &&
getToolChain().getTriple().isOSLinux())
SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output,
SplitDebugName(JA, Args, Inputs[0], Output));
}
namespace {
// Filter to remove Multilibs that don't exist as a suffix to Path
class FilterNonExistent {
StringRef Base, File;
llvm::vfs::FileSystem &VFS;
public:
FilterNonExistent(StringRef Base, StringRef File, llvm::vfs::FileSystem &VFS)
: Base(Base), File(File), VFS(VFS) {}
bool operator()(const Multilib &M) {
return !VFS.exists(Base + M.gccSuffix() + File);
}
};
} // end anonymous namespace
static bool isSoftFloatABI(const ArgList &Args) {
Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
options::OPT_mfloat_abi_EQ);
if (!A)
return false;
return A->getOption().matches(options::OPT_msoft_float) ||
(A->getOption().matches(options::OPT_mfloat_abi_EQ) &&
A->getValue() == StringRef("soft"));
}
static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) {
return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb;
}
static bool isMipsEL(llvm::Triple::ArchType Arch) {
return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el;
}
static bool isMips16(const ArgList &Args) {
Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16);
return A && A->getOption().matches(options::OPT_mips16);
}
static bool isMicroMips(const ArgList &Args) {
Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips);
return A && A->getOption().matches(options::OPT_mmicromips);
}
static bool isMSP430(llvm::Triple::ArchType Arch) {
return Arch == llvm::Triple::msp430;
}
static Multilib makeMultilib(StringRef commonSuffix) {
return Multilib(commonSuffix, commonSuffix, commonSuffix);
}
static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
// Check for Code Sourcery toolchain multilibs
MultilibSet CSMipsMultilibs;
{
auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16");
auto MArchMicroMips =
makeMultilib("/micromips").flag("+m32").flag("+mmicromips");
auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips");
auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float");
auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
auto DefaultFloat =
makeMultilib("").flag("-msoft-float").flag("-mnan=2008");
auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
// Note that this one's osSuffix is ""
auto MAbi64 = makeMultilib("")
.gccSuffix("/64")
.includeSuffix("/64")
.flag("+mabi=n64")
.flag("-mabi=n32")
.flag("-m32");
CSMipsMultilibs =
MultilibSet()
.Either(MArchMips16, MArchMicroMips, MArchDefault)
.Maybe(UCLibc)
.Either(SoftFloat, Nan2008, DefaultFloat)
.FilterOut("/micromips/nan2008")
.FilterOut("/mips16/nan2008")
.Either(BigEndian, LittleEndian)
.Maybe(MAbi64)
.FilterOut("/mips16.*/64")
.FilterOut("/micromips.*/64")
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
if (StringRef(M.includeSuffix()).startswith("/uclibc"))
Dirs.push_back(
"/../../../../mips-linux-gnu/libc/uclibc/usr/include");
else
Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include");
return Dirs;
});
}
MultilibSet DebianMipsMultilibs;
{
Multilib MAbiN32 =
Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32");
Multilib M64 = Multilib()
.gccSuffix("/64")
.includeSuffix("/64")
.flag("+m64")
.flag("-m32")
.flag("-mabi=n32");
Multilib M32 =
Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32");
DebianMipsMultilibs =
MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent);
}
// Sort candidates. Toolchain that best meets the directories tree goes first.
// Then select the first toolchains matches command line flags.
MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs};
if (CSMipsMultilibs.size() < DebianMipsMultilibs.size())
std::iter_swap(Candidates, Candidates + 1);
for (const MultilibSet *Candidate : Candidates) {
if (Candidate->select(Flags, Result.SelectedMultilib)) {
if (Candidate == &DebianMipsMultilibs)
Result.BiarchSibling = Multilib();
Result.Multilibs = *Candidate;
return true;
}
}
return false;
}
static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
MultilibSet AndroidMipsMultilibs =
MultilibSet()
.Maybe(Multilib("/mips-r2").flag("+march=mips32r2"))
.Maybe(Multilib("/mips-r6").flag("+march=mips32r6"))
.FilterOut(NonExistent);
MultilibSet AndroidMipselMultilibs =
MultilibSet()
.Either(Multilib().flag("+march=mips32"),
Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
.FilterOut(NonExistent);
MultilibSet AndroidMips64elMultilibs =
MultilibSet()
.Either(
Multilib().flag("+march=mips64r6"),
Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"),
Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"),
Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6"))
.FilterOut(NonExistent);
MultilibSet *MS = &AndroidMipsMultilibs;
if (VFS.exists(Path + "/mips-r6"))
MS = &AndroidMipselMultilibs;
else if (VFS.exists(Path + "/32"))
MS = &AndroidMips64elMultilibs;
if (MS->select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = *MS;
return true;
}
return false;
}
static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
// Musl toolchain multilibs
MultilibSet MuslMipsMultilibs;
{
auto MArchMipsR2 = makeMultilib("")
.osSuffix("/mips-r2-hard-musl")
.flag("+EB")
.flag("-EL")
.flag("+march=mips32r2");
auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl")
.flag("-EB")
.flag("+EL")
.flag("+march=mips32r2");
MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2);
// Specify the callback that computes the include directories.
MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>(
{"/../sysroot" + M.osSuffix() + "/usr/include"});
});
}
if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = MuslMipsMultilibs;
return true;
}
return false;
}
static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
// CodeScape MTI toolchain v1.2 and early.
MultilibSet MtiMipsMultilibsV1;
{
auto MArchMips32 = makeMultilib("/mips32")
.flag("+m32")
.flag("-m64")
.flag("-mmicromips")
.flag("+march=mips32");
auto MArchMicroMips = makeMultilib("/micromips")
.flag("+m32")
.flag("-m64")
.flag("+mmicromips");
auto MArchMips64r2 = makeMultilib("/mips64r2")
.flag("-m32")
.flag("+m64")
.flag("+march=mips64r2");
auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag(
"-march=mips64r2");
auto MArchDefault = makeMultilib("")
.flag("+m32")
.flag("-m64")
.flag("-mmicromips")
.flag("+march=mips32r2");
auto Mips16 = makeMultilib("/mips16").flag("+mips16");
auto UCLibc = makeMultilib("/uclibc").flag("+muclibc");
auto MAbi64 =
makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
auto BigEndian = makeMultilib("").flag("+EB").flag("-EL");
auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
auto SoftFloat = makeMultilib("/sof").flag("+msoft-float");
auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008");
MtiMipsMultilibsV1 =
MultilibSet()
.Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64,
MArchDefault)
.Maybe(UCLibc)
.Maybe(Mips16)
.FilterOut("/mips64/mips16")
.FilterOut("/mips64r2/mips16")
.FilterOut("/micromips/mips16")
.Maybe(MAbi64)
.FilterOut("/micromips/64")
.FilterOut("/mips32/64")
.FilterOut("^/64")
.FilterOut("/mips16/64")
.Either(BigEndian, LittleEndian)
.Maybe(SoftFloat)
.Maybe(Nan2008)
.FilterOut(".*sof/nan2008")
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
if (StringRef(M.includeSuffix()).startswith("/uclibc"))
Dirs.push_back("/../../../../sysroot/uclibc/usr/include");
else
Dirs.push_back("/../../../../sysroot/usr/include");
return Dirs;
});
}
// CodeScape IMG toolchain starting from v1.3.
MultilibSet MtiMipsMultilibsV2;
{
auto BeHard = makeMultilib("/mips-r2-hard")
.flag("+EB")
.flag("-msoft-float")
.flag("-mnan=2008")
.flag("-muclibc");
auto BeSoft = makeMultilib("/mips-r2-soft")
.flag("+EB")
.flag("+msoft-float")
.flag("-mnan=2008");
auto ElHard = makeMultilib("/mipsel-r2-hard")
.flag("+EL")
.flag("-msoft-float")
.flag("-mnan=2008")
.flag("-muclibc");
auto ElSoft = makeMultilib("/mipsel-r2-soft")
.flag("+EL")
.flag("+msoft-float")
.flag("-mnan=2008")
.flag("-mmicromips");
auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008")
.flag("+EB")
.flag("-msoft-float")
.flag("+mnan=2008")
.flag("-muclibc");
auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008")
.flag("+EL")
.flag("-msoft-float")
.flag("+mnan=2008")
.flag("-muclibc")
.flag("-mmicromips");
auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc")
.flag("+EB")
.flag("-msoft-float")
.flag("+mnan=2008")
.flag("+muclibc");
auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc")
.flag("+EL")
.flag("-msoft-float")
.flag("+mnan=2008")
.flag("+muclibc");
auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc")
.flag("+EB")
.flag("-msoft-float")
.flag("-mnan=2008")
.flag("+muclibc");
auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc")
.flag("+EL")
.flag("-msoft-float")
.flag("-mnan=2008")
.flag("+muclibc");
auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008")
.flag("+EL")
.flag("-msoft-float")
.flag("+mnan=2008")
.flag("+mmicromips");
auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft")
.flag("+EL")
.flag("+msoft-float")
.flag("-mnan=2008")
.flag("+mmicromips");
auto O32 =
makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
auto N32 =
makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
auto N64 =
makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
MtiMipsMultilibsV2 =
MultilibSet()
.Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan,
BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc,
ElHardUclibc, ElMicroHardNan, ElMicroSoft})
.Either(O32, N32, N64)
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>({"/../../../../sysroot" +
M.includeSuffix() +
"/../usr/include"});
})
.setFilePathsCallback([](const Multilib &M) {
return std::vector<std::string>(
{"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()});
});
}
for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
if (Candidate->select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = *Candidate;
return true;
}
}
return false;
}
static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
FilterNonExistent &NonExistent,
DetectedMultilibs &Result) {
// CodeScape IMG toolchain v1.2 and early.
MultilibSet ImgMultilibsV1;
{
auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32");
auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB");
auto MAbi64 =
makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32");
ImgMultilibsV1 =
MultilibSet()
.Maybe(Mips64r6)
.Maybe(MAbi64)
.Maybe(LittleEndian)
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>(
{"/include", "/../../../../sysroot/usr/include"});
});
}
// CodeScape IMG toolchain starting from v1.3.
MultilibSet ImgMultilibsV2;
{
auto BeHard = makeMultilib("/mips-r6-hard")
.flag("+EB")
.flag("-msoft-float")
.flag("-mmicromips");
auto BeSoft = makeMultilib("/mips-r6-soft")
.flag("+EB")
.flag("+msoft-float")
.flag("-mmicromips");
auto ElHard = makeMultilib("/mipsel-r6-hard")
.flag("+EL")
.flag("-msoft-float")
.flag("-mmicromips");
auto ElSoft = makeMultilib("/mipsel-r6-soft")
.flag("+EL")
.flag("+msoft-float")
.flag("-mmicromips");
auto BeMicroHard = makeMultilib("/micromips-r6-hard")
.flag("+EB")
.flag("-msoft-float")
.flag("+mmicromips");
auto BeMicroSoft = makeMultilib("/micromips-r6-soft")
.flag("+EB")
.flag("+msoft-float")
.flag("+mmicromips");
auto ElMicroHard = makeMultilib("/micromipsel-r6-hard")
.flag("+EL")
.flag("-msoft-float")
.flag("+mmicromips");
auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft")
.flag("+EL")
.flag("+msoft-float")
.flag("+mmicromips");
auto O32 =
makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64");
auto N32 =
makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64");
auto N64 =
makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64");
ImgMultilibsV2 =
MultilibSet()
.Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft,
ElMicroHard, ElMicroSoft})
.Either(O32, N32, N64)
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
return std::vector<std::string>({"/../../../../sysroot" +
M.includeSuffix() +
"/../usr/include"});
})
.setFilePathsCallback([](const Multilib &M) {
return std::vector<std::string>(
{"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()});
});
}
for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
if (Candidate->select(Flags, Result.SelectedMultilib)) {
Result.Multilibs = *Candidate;
return true;
}
}
return false;
}
bool clang::driver::findMIPSMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
StringRef CPUName;
StringRef ABIName;
tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName);
llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
Multilib::flags_list Flags;
addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags);
addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags);
addMultilibFlag(isMips16(Args), "mips16", Flags);
addMultilibFlag(CPUName == "mips32", "march=mips32", Flags);
addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" ||
CPUName == "mips32r5" || CPUName == "p5600",
"march=mips32r2", Flags);
addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags);
addMultilibFlag(CPUName == "mips64", "march=mips64", Flags);
addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" ||
CPUName == "mips64r5" || CPUName == "octeon" ||
CPUName == "octeon+",
"march=mips64r2", Flags);
addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags);
addMultilibFlag(isMicroMips(Args), "mmicromips", Flags);
addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags);
addMultilibFlag(tools::mips::isNaN2008(D, Args, TargetTriple), "mnan=2008",
Flags);
addMultilibFlag(ABIName == "n32", "mabi=n32", Flags);
addMultilibFlag(ABIName == "n64", "mabi=n64", Flags);
addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags);
addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags);
addMultilibFlag(isMipsEL(TargetArch), "EL", Flags);
addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags);
if (TargetTriple.isAndroid())
return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent,
Result);
if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment)
return findMipsMuslMultilibs(Flags, NonExistent, Result);
if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
TargetTriple.isGNUEnvironment())
return findMipsMtiMultilibs(Flags, NonExistent, Result);
if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
TargetTriple.getOS() == llvm::Triple::Linux &&
TargetTriple.isGNUEnvironment())
return findMipsImgMultilibs(Flags, NonExistent, Result);
if (findMipsCsMultilibs(Flags, NonExistent, Result))
return true;
// Fallback to the regular toolchain-tree structure.
Multilib Default;
Result.Multilibs.push_back(Default);
Result.Multilibs.FilterOut(NonExistent);
if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
Result.BiarchSibling = Multilib();
return true;
}
return false;
}
static void findAndroidArmMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
// Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb.
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
Multilib ArmV7Multilib = makeMultilib("/armv7-a")
.flag("+march=armv7-a")
.flag("-mthumb");
Multilib ThumbMultilib = makeMultilib("/thumb")
.flag("-march=armv7-a")
.flag("+mthumb");
Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
.flag("+march=armv7-a")
.flag("+mthumb");
Multilib DefaultMultilib = makeMultilib("")
.flag("-march=armv7-a")
.flag("-mthumb");
MultilibSet AndroidArmMultilibs =
MultilibSet()
.Either(ThumbMultilib, ArmV7Multilib,
ArmV7ThumbMultilib, DefaultMultilib)
.FilterOut(NonExistent);
Multilib::flags_list Flags;
llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ);
bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm;
bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb;
bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7;
bool IsThumbMode = IsThumbArch ||
Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) ||
(IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB);
bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
(llvm::ARM::parseArchVersion(Arch) == 7 ||
(IsArmArch && Arch == "" && IsV7SubArch));
addMultilibFlag(IsArmV7Mode, "march=armv7-a", Flags);
addMultilibFlag(IsThumbMode, "mthumb", Flags);
if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
Result.Multilibs = AndroidArmMultilibs;
}
static bool findMSP430Multilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions");
Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions");
// FIXME: when clang starts to support msp430x ISA additional logic
// to select between multilib must be implemented
// Multilib MSP430xMultilib = makeMultilib("/large");
Result.Multilibs.push_back(WithoutExceptions);
Result.Multilibs.push_back(WithExceptions);
Result.Multilibs.FilterOut(NonExistent);
Multilib::flags_list Flags;
addMultilibFlag(Args.hasFlag(options::OPT_fexceptions,
options::OPT_fno_exceptions, false),
"exceptions", Flags);
if (Result.Multilibs.select(Flags, Result.SelectedMultilib))
return true;
return false;
}
static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
tools::csky::FloatABI TheFloatABI = tools::csky::getCSKYFloatABI(D, Args);
llvm::Optional<llvm::StringRef> Res = tools::csky::getCSKYArchName(D, Args, TargetTriple);
if (!Res)
return;
auto ARCHName = *Res;
Multilib::flags_list Flags;
addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Hard, "hard-fp", Flags);
addMultilibFlag(TheFloatABI == tools::csky::FloatABI::SoftFP, "soft-fp",
Flags);
addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Soft, "soft", Flags);
addMultilibFlag(ARCHName == "ck801", "march=ck801", Flags);
addMultilibFlag(ARCHName == "ck802", "march=ck802", Flags);
addMultilibFlag(ARCHName == "ck803", "march=ck803", Flags);
addMultilibFlag(ARCHName == "ck804", "march=ck804", Flags);
addMultilibFlag(ARCHName == "ck805", "march=ck805", Flags);
addMultilibFlag(ARCHName == "ck807", "march=ck807", Flags);
addMultilibFlag(ARCHName == "ck810", "march=ck810", Flags);
addMultilibFlag(ARCHName == "ck810v", "march=ck810v", Flags);
addMultilibFlag(ARCHName == "ck860", "march=ck860", Flags);
addMultilibFlag(ARCHName == "ck860v", "march=ck860v", Flags);
bool isBigEndian = false;
if (Arg *A = Args.getLastArg(options::OPT_mlittle_endian,
options::OPT_mbig_endian))
isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian);
addMultilibFlag(isBigEndian, "EB", Flags);
auto HardFloat = makeMultilib("/hard-fp").flag("+hard-fp");
auto SoftFpFloat = makeMultilib("/soft-fp").flag("+soft-fp");
auto SoftFloat = makeMultilib("").flag("+soft");
auto Arch801 = makeMultilib("/ck801").flag("+march=ck801");
auto Arch802 = makeMultilib("/ck802").flag("+march=ck802");
auto Arch803 = makeMultilib("/ck803").flag("+march=ck803");
// CK804 use the same library as CK803
auto Arch804 = makeMultilib("/ck803").flag("+march=ck804");
auto Arch805 = makeMultilib("/ck805").flag("+march=ck805");
auto Arch807 = makeMultilib("/ck807").flag("+march=ck807");
auto Arch810 = makeMultilib("").flag("+march=ck810");
auto Arch810v = makeMultilib("/ck810v").flag("+march=ck810v");
auto Arch860 = makeMultilib("/ck860").flag("+march=ck860");
auto Arch860v = makeMultilib("/ck860v").flag("+march=ck860v");
auto BigEndian = makeMultilib("/big").flag("+EB");
MultilibSet CSKYMultilibs =
MultilibSet()
.Maybe(BigEndian)
.Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807,
Arch810, Arch810v, Arch860, Arch860v})
.Either(HardFloat, SoftFpFloat, SoftFloat)
.FilterOut(NonExistent);
if (CSKYMultilibs.select(Flags, Result.SelectedMultilib))
Result.Multilibs = CSKYMultilibs;
}
static void findRISCVBareMetalMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
DetectedMultilibs &Result) {
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
struct RiscvMultilib {
StringRef march;
StringRef mabi;
};
// currently only support the set of multilibs like riscv-gnu-toolchain does.
// TODO: support MULTILIB_REUSE
constexpr RiscvMultilib RISCVMultilibSet[] = {
{"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"},
{"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
{"rv64imafdc", "lp64d"}};
std::vector<Multilib> Ms;
for (auto Element : RISCVMultilibSet) {
// multilib path rule is ${march}/${mabi}
Ms.emplace_back(
makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str())
.flag(Twine("+march=", Element.march).str())
.flag(Twine("+mabi=", Element.mabi).str()));
}
MultilibSet RISCVMultilibs =
MultilibSet()
.Either(ArrayRef<Multilib>(Ms))
.FilterOut(NonExistent)
.setFilePathsCallback([](const Multilib &M) {
return std::vector<std::string>(
{M.gccSuffix(),
"/../../../../riscv64-unknown-elf/lib" + M.gccSuffix(),
"/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()});
});
Multilib::flags_list Flags;
llvm::StringSet<> Added_ABIs;
StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple);
for (auto Element : RISCVMultilibSet) {
addMultilibFlag(MArch == Element.march,
Twine("march=", Element.march).str().c_str(), Flags);
if (!Added_ABIs.count(Element.mabi)) {
Added_ABIs.insert(Element.mabi);
addMultilibFlag(ABIName == Element.mabi,
Twine("mabi=", Element.mabi).str().c_str(), Flags);
}
}
if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
Result.Multilibs = RISCVMultilibs;
}
static void findRISCVMultilibs(const Driver &D,
const llvm::Triple &TargetTriple, StringRef Path,
const ArgList &Args, DetectedMultilibs &Result) {
if (TargetTriple.getOS() == llvm::Triple::UnknownOS)
return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result);
FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS());
Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32");
Multilib Ilp32f =
makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f");
Multilib Ilp32d =
makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d");
Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64");
Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f");
Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d");
MultilibSet RISCVMultilibs =
MultilibSet()
.Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d})
.FilterOut(NonExistent);
Multilib::flags_list Flags;
bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64;
StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple);
addMultilibFlag(!IsRV64, "m32", Flags);
addMultilibFlag(IsRV64, "m64", Flags);
addMultilibFlag(ABIName == "ilp32", "mabi=ilp32", Flags);
addMultilibFlag(ABIName == "ilp32f", "mabi=ilp32f", Flags);
addMultilibFlag(ABIName == "ilp32d", "mabi=ilp32d", Flags);
addMultilibFlag(ABIName == "lp64", "mabi=lp64", Flags);
addMultilibFlag(ABIName == "lp64f", "mabi=lp64f", Flags);
addMultilibFlag(ABIName == "lp64d", "mabi=lp64d", Flags);
if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
Result.Multilibs = RISCVMultilibs;
}
static bool findBiarchMultilibs(const Driver &D,
const llvm::Triple &TargetTriple,
StringRef Path, const ArgList &Args,
bool NeedsBiarchSuffix,
DetectedMultilibs &Result) {
Multilib Default;
// Some versions of SUSE and Fedora on ppc64 put 32-bit libs
// in what would normally be GCCInstallPath and put the 64-bit
// libs in a subdirectory named 64. The simple logic we follow is that
// *if* there is a subdirectory of the right name with crtbegin.o in it,
// we use that. If not, and if not a biarch triple alias, we look for
// crtbegin.o without the subdirectory.
StringRef Suff64 = "/64";
// Solaris uses platform-specific suffixes instead of /64.
if (TargetTriple.getOS() == llvm::Triple::Solaris) {
switch (TargetTriple.getArch()) {
case llvm::Triple::x86:
case llvm::Triple::x86_64:
Suff64 = "/amd64";
break;
case llvm::Triple::sparc:
case llvm::Triple::sparcv9:
Suff64 = "/sparcv9";
break;
default:
break;
}
}
Multilib Alt64 = Multilib()
.gccSuffix(Suff64)
.includeSuffix(Suff64)
.flag("-m32")
.flag("+m64")
.flag("-mx32");
Multilib Alt32 = Multilib()
.gccSuffix("/32")
.includeSuffix("/32")
.flag("+m32")
.flag("-m64")
.flag("-mx32");
Multilib Altx32 = Multilib()
.gccSuffix("/x32")
.includeSuffix("/x32")
.flag("-m32")
.flag("-m64")
.flag("+mx32");
// GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a.
FilterNonExistent NonExistent(
Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS());
// Determine default multilib from: 32, 64, x32
// Also handle cases such as 64 on 32, 32 on 64, etc.
enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN;
const bool IsX32 = TargetTriple.isX32();
if (TargetTriple.isArch32Bit() && !NonExistent(Alt32))
Want = WANT64;
else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32))
Want = WANT64;
else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64))
Want = WANT32;
else {
if (TargetTriple.isArch32Bit())
Want = NeedsBiarchSuffix ? WANT64 : WANT32;
else if (IsX32)
Want = NeedsBiarchSuffix ? WANT64 : WANTX32;
else
Want = NeedsBiarchSuffix ? WANT32 : WANT64;
}
if (Want == WANT32)
Default.flag("+m32").flag("-m64").flag("-mx32");
else if (Want == WANT64)
Default.flag("-m32").flag("+m64").flag("-mx32");
else if (Want == WANTX32)
Default.flag("-m32").flag("-m64").flag("+mx32");
else
return false;
Result.Multilibs.push_back(Default);
Result.Multilibs.push_back(Alt64);
Result.Multilibs.push_back(Alt32);
Result.Multilibs.push_back(Altx32);
Result.Multilibs.FilterOut(NonExistent);
Multilib::flags_list Flags;
addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags);
addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags);
addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags);
if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
return false;
if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 ||
Result.SelectedMultilib == Altx32)
Result.BiarchSibling = Default;
return true;
}
/// Generic_GCC - A tool chain using the 'gcc' command to perform
/// all subcommands; this relies on gcc translating the majority of
/// command line options.
/// Less-than for GCCVersion, implementing a Strict Weak Ordering.
bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor,
int RHSPatch,
StringRef RHSPatchSuffix) const {
if (Major != RHSMajor)
return Major < RHSMajor;
if (Minor != RHSMinor)
return Minor < RHSMinor;
if (Patch != RHSPatch) {
// Note that versions without a specified patch sort higher than those with
// a patch.
if (RHSPatch == -1)
return true;
if (Patch == -1)
return false;
// Otherwise just sort on the patch itself.
return Patch < RHSPatch;
}
if (PatchSuffix != RHSPatchSuffix) {
// Sort empty suffixes higher.
if (RHSPatchSuffix.empty())
return true;
if (PatchSuffix.empty())
return false;
// Provide a lexicographic sort to make this a total ordering.
return PatchSuffix < RHSPatchSuffix;
}
// The versions are equal.
return false;
}
/// Parse a GCCVersion object out of a string of text.
///
/// This is the primary means of forming GCCVersion objects.
/*static*/
Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
std::pair<StringRef, StringRef> First = VersionText.split('.');
std::pair<StringRef, StringRef> Second = First.second.split('.');
GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""};
if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0)
return BadVersion;
GoodVersion.MajorStr = First.first.str();
if (First.second.empty())
return GoodVersion;
StringRef MinorStr = Second.first;
if (Second.second.empty()) {
if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) {
GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber));
MinorStr = MinorStr.slice(0, EndNumber);
}
}
if (MinorStr.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0)
return BadVersion;
GoodVersion.MinorStr = MinorStr.str();
// First look for a number prefix and parse that if present. Otherwise just
// stash the entire patch string in the suffix, and leave the number
// unspecified. This covers versions strings such as:
// 5 (handled above)
// 4.4
// 4.4-patched
// 4.4.0
// 4.4.x
// 4.4.2-rc4
// 4.4.x-patched
// And retains any patch number it finds.
StringRef PatchText = Second.second;
if (!PatchText.empty()) {
if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) {
// Try to parse the number and any suffix.
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
GoodVersion.Patch < 0)
return BadVersion;
GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber));
}
}
return GoodVersion;
}
static llvm::StringRef getGCCToolchainDir(const ArgList &Args,
llvm::StringRef SysRoot) {
const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
if (A)
return A->getValue();
// If we have a SysRoot, ignore GCC_INSTALL_PREFIX.
// GCC_INSTALL_PREFIX specifies the gcc installation for the default
// sysroot and is likely not valid with a different sysroot.
if (!SysRoot.empty())
return "";
return GCC_INSTALL_PREFIX;
}
/// Initialize a GCCInstallationDetector from the driver.
///
/// This performs all of the autodetection and sets up the various paths.
/// Once constructed, a GCCInstallationDetector is essentially immutable.
///
/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
/// should instead pull the target out of the driver. This is currently
/// necessary because the driver doesn't store the final version of the target
/// triple.
void Generic_GCC::GCCInstallationDetector::init(
const llvm::Triple &TargetTriple, const ArgList &Args,
ArrayRef<std::string> ExtraTripleAliases) {
llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit()
? TargetTriple.get64BitArchVariant()
: TargetTriple.get32BitArchVariant();
// The library directories which may contain GCC installations.
SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs;
// The compatible GCC triples for this particular architecture.
SmallVector<StringRef, 16> CandidateTripleAliases;
SmallVector<StringRef, 16> CandidateBiarchTripleAliases;
CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs,
CandidateTripleAliases, CandidateBiarchLibDirs,
CandidateBiarchTripleAliases);
// Compute the set of prefixes for our search.
SmallVector<std::string, 8> Prefixes;
StringRef GCCToolchainDir = getGCCToolchainDir(Args, D.SysRoot);
if (GCCToolchainDir != "") {
if (GCCToolchainDir.back() == '/')
GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
Prefixes.push_back(std::string(GCCToolchainDir));
} else {
// If we have a SysRoot, try that first.
if (!D.SysRoot.empty()) {
Prefixes.push_back(D.SysRoot);
AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot);
}
// Then look for gcc installed alongside clang.
Prefixes.push_back(D.InstalledDir + "/..");
// Next, look for prefix(es) that correspond to distribution-supplied gcc
// installations.
if (D.SysRoot.empty()) {
// Typically /usr.
AddDefaultGCCPrefixes(TargetTriple, Prefixes, D.SysRoot);
}
// Try to respect gcc-config on Gentoo if --gcc-toolchain is not provided.
// This avoids accidentally enforcing the system GCC version when using a
// custom toolchain.
SmallVector<StringRef, 16> GentooTestTriples;
// Try to match an exact triple as target triple first.
// e.g. crossdev -S x86_64-gentoo-linux-gnu will install gcc libs for
// x86_64-gentoo-linux-gnu. But "clang -target x86_64-gentoo-linux-gnu"
// may pick the libraries for x86_64-pc-linux-gnu even when exact matching
// triple x86_64-gentoo-linux-gnu is present.
GentooTestTriples.push_back(TargetTriple.str());
// Check rest of triples.
GentooTestTriples.append(ExtraTripleAliases.begin(),
ExtraTripleAliases.end());
GentooTestTriples.append(CandidateTripleAliases.begin(),
CandidateTripleAliases.end());
if (ScanGentooConfigs(TargetTriple, Args, GentooTestTriples,
CandidateBiarchTripleAliases))
return;
}
// Loop over the various components which exist and select the best GCC
// installation available. GCC installs are ranked by version number.
const GCCVersion VersionZero = GCCVersion::Parse("0.0.0");
Version = VersionZero;
for (const std::string &Prefix : Prefixes) {
auto &VFS = D.getVFS();
if (!VFS.exists(Prefix))
continue;
for (StringRef Suffix : CandidateLibDirs) {
const std::string LibDir = concat(Prefix, Suffix);
if (!VFS.exists(LibDir))
continue;
// Maybe filter out <libdir>/gcc and <libdir>/gcc-cross.
bool GCCDirExists = VFS.exists(LibDir + "/gcc");
bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross");
// Try to match the exact target triple first.
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, TargetTriple.str(),
false, GCCDirExists, GCCCrossDirExists);
// Try rest of possible triples.
for (StringRef Candidate : ExtraTripleAliases) // Try these first.
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false,
GCCDirExists, GCCCrossDirExists);
for (StringRef Candidate : CandidateTripleAliases)
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, false,
GCCDirExists, GCCCrossDirExists);
}
for (StringRef Suffix : CandidateBiarchLibDirs) {
const std::string LibDir = Prefix + Suffix.str();
if (!VFS.exists(LibDir))
continue;
bool GCCDirExists = VFS.exists(LibDir + "/gcc");
bool GCCCrossDirExists = VFS.exists(LibDir + "/gcc-cross");
for (StringRef Candidate : CandidateBiarchTripleAliases)
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, true,
GCCDirExists, GCCCrossDirExists);
}
// Skip other prefixes once a GCC installation is found.
if (Version > VersionZero)
break;
}
}
void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const {
for (const auto &InstallPath : CandidateGCCInstallPaths)
OS << "Found candidate GCC installation: " << InstallPath << "\n";
if (!GCCInstallPath.empty())
OS << "Selected GCC installation: " << GCCInstallPath << "\n";
for (const auto &Multilib : Multilibs)
OS << "Candidate multilib: " << Multilib << "\n";
if (Multilibs.size() != 0 || !SelectedMultilib.isDefault())
OS << "Selected multilib: " << SelectedMultilib << "\n";
}
bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const {
if (BiarchSibling) {
M = BiarchSibling.value();
return true;
}
return false;
}
void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
const llvm::Triple &TargetTriple, SmallVectorImpl<std::string> &Prefixes,
StringRef SysRoot) {
if (TargetTriple.getOS() == llvm::Triple::Solaris) {
// Solaris is a special case.
// The GCC installation is under
// /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/
// so we need to find those /usr/gcc/*/lib/gcc libdirs and go with
// /usr/gcc/<version> as a prefix.
std::string PrefixDir = concat(SysRoot, "/usr/gcc");
std::error_code EC;
for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin(PrefixDir, EC),
LE;
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef VersionText = llvm::sys::path::filename(LI->path());
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
// Filter out obviously bad entries.
if (CandidateVersion.Major == -1 || CandidateVersion.isOlderThan(4, 1, 1))
continue;
std::string CandidatePrefix = PrefixDir + "/" + VersionText.str();
std::string CandidateLibPath = CandidatePrefix + "/lib/gcc";
if (!D.getVFS().exists(CandidateLibPath))
continue;
Prefixes.push_back(CandidatePrefix);
}
return;
}
// For Linux, if --sysroot is not specified, look for RHEL/CentOS devtoolsets
// and gcc-toolsets.
if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux &&
D.getVFS().exists("/opt/rh")) {
// Find the directory in /opt/rh/ starting with gcc-toolset-* or
// devtoolset-* with the highest version number and add that
// one to our prefixes.
std::string ChosenToolsetDir;
unsigned ChosenToolsetVersion = 0;
std::error_code EC;
for (llvm::vfs::directory_iterator LI = D.getVFS().dir_begin("/opt/rh", EC),
LE;
!EC && LI != LE; LI = LI.increment(EC)) {
StringRef ToolsetDir = llvm::sys::path::filename(LI->path());
unsigned ToolsetVersion;
if ((!ToolsetDir.startswith("gcc-toolset-") &&
!ToolsetDir.startswith("devtoolset-")) ||
ToolsetDir.substr(ToolsetDir.rfind('-') + 1)
.getAsInteger(10, ToolsetVersion))
continue;
if (ToolsetVersion > ChosenToolsetVersion) {
ChosenToolsetVersion = ToolsetVersion;
ChosenToolsetDir = "/opt/rh/" + ToolsetDir.str();
}
}
if (ChosenToolsetVersion > 0)
Prefixes.push_back(ChosenToolsetDir + "/root/usr");
}
// Fall back to /usr which is used by most non-Solaris systems.
Prefixes.push_back(concat(SysRoot, "/usr"));
}
/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple,
SmallVectorImpl<StringRef> &LibDirs,
SmallVectorImpl<StringRef> &TripleAliases,
SmallVectorImpl<StringRef> &BiarchLibDirs,
SmallVectorImpl<StringRef> &BiarchTripleAliases) {
// Declare a bunch of static data sets that we'll select between below. These
// are specifically designed to always refer to string literals to avoid any
// lifetime or initialization issues.
//
// The *Triples variables hard code some triples so that, for example,
// --target=aarch64 (incomplete triple) can detect lib/aarch64-linux-gnu.
// They are not needed when the user has correct LLVM_DEFAULT_TARGET_TRIPLE
// and always uses the full --target (e.g. --target=aarch64-linux-gnu). The
// lists should shrink over time. Please don't add more elements to *Triples.
static const char *const AArch64LibDirs[] = {"/lib64", "/lib"};
static const char *const AArch64Triples[] = {
"aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-redhat-linux",
"aarch64-suse-linux"};
static const char *const AArch64beLibDirs[] = {"/lib"};
static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu",
"aarch64_be-linux-gnu"};
static const char *const ARMLibDirs[] = {"/lib"};
static const char *const ARMTriples[] = {"arm-linux-gnueabi"};
static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf",
"armv7hl-redhat-linux-gnueabi",
"armv6hl-suse-linux-gnueabi",
"armv7hl-suse-linux-gnueabi"};
static const char *const ARMebLibDirs[] = {"/lib"};
static const char *const ARMebTriples[] = {"armeb-linux-gnueabi"};
static const char *const ARMebHFTriples[] = {
"armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
static const char *const AVRLibDirs[] = {"/lib"};
static const char *const AVRTriples[] = {"avr"};
static const char *const CSKYLibDirs[] = {"/lib"};
static const char *const CSKYTriples[] = {
"csky-linux-gnuabiv2", "csky-linux-uclibcabiv2", "csky-elf-noneabiv2"};
static const char *const X86_64LibDirs[] = {"/lib64", "/lib"};
static const char *const X86_64Triples[] = {
"x86_64-linux-gnu", "x86_64-unknown-linux-gnu",
"x86_64-pc-linux-gnu", "x86_64-redhat-linux6E",
"x86_64-redhat-linux", "x86_64-suse-linux",
"x86_64-manbo-linux-gnu", "x86_64-linux-gnu",
"x86_64-slackware-linux", "x86_64-unknown-linux",
"x86_64-amazon-linux"};
static const char *const X32Triples[] = {"x86_64-linux-gnux32",
"x86_64-pc-linux-gnux32"};
static const char *const X32LibDirs[] = {"/libx32", "/lib"};
static const char *const X86LibDirs[] = {"/lib32", "/lib"};
static const char *const X86Triples[] = {
"i586-linux-gnu", "i686-linux-gnu", "i686-pc-linux-gnu",
"i386-redhat-linux6E", "i686-redhat-linux", "i386-redhat-linux",
"i586-suse-linux", "i686-montavista-linux", "i686-gnu",
};
static const char *const M68kLibDirs[] = {"/lib"};
static const char *const M68kTriples[] = {
"m68k-linux-gnu", "m68k-unknown-linux-gnu", "m68k-suse-linux"};
static const char *const MIPSLibDirs[] = {"/libo32", "/lib"};
static const char *const MIPSTriples[] = {
"mips-linux-gnu", "mips-mti-linux", "mips-mti-linux-gnu",
"mips-img-linux-gnu", "mipsisa32r6-linux-gnu"};
static const char *const MIPSELLibDirs[] = {"/libo32", "/lib"};
static const char *const MIPSELTriples[] = {
"mipsel-linux-gnu", "mips-img-linux-gnu", "mipsisa32r6el-linux-gnu"};
static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"};
static const char *const MIPS64Triples[] = {
"mips64-linux-gnu", "mips-mti-linux-gnu",
"mips-img-linux-gnu", "mips64-linux-gnuabi64",
"mipsisa64r6-linux-gnu", "mipsisa64r6-linux-gnuabi64"};
static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"};
static const char *const MIPS64ELTriples[] = {
"mips64el-linux-gnu", "mips-mti-linux-gnu",
"mips-img-linux-gnu", "mips64el-linux-gnuabi64",
"mipsisa64r6el-linux-gnu", "mipsisa64r6el-linux-gnuabi64"};
static const char *const MIPSN32LibDirs[] = {"/lib32"};
static const char *const MIPSN32Triples[] = {"mips64-linux-gnuabin32",
"mipsisa64r6-linux-gnuabin32"};
static const char *const MIPSN32ELLibDirs[] = {"/lib32"};
static const char *const MIPSN32ELTriples[] = {
"mips64el-linux-gnuabin32", "mipsisa64r6el-linux-gnuabin32"};
static const char *const MSP430LibDirs[] = {"/lib"};
static const char *const MSP430Triples[] = {"msp430-elf"};
static const char *const PPCLibDirs[] = {"/lib32", "/lib"};
static const char *const PPCTriples[] = {
"powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
// On 32-bit PowerPC systems running SUSE Linux, gcc is configured as a
// 64-bit compiler which defaults to "-m32", hence "powerpc64-suse-linux".
"powerpc64-suse-linux", "powerpc-montavista-linuxspe"};
static const char *const PPCLELibDirs[] = {"/lib32", "/lib"};
static const char *const PPCLETriples[] = {"powerpcle-linux-gnu",
"powerpcle-unknown-linux-gnu",
"powerpcle-linux-musl"};
static const char *const PPC64LibDirs[] = {"/lib64", "/lib"};
static const char *const PPC64Triples[] = {
"powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu",
"powerpc64-suse-linux", "ppc64-redhat-linux"};
static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"};
static const char *const PPC64LETriples[] = {
"powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu",
"powerpc64le-none-linux-gnu", "powerpc64le-suse-linux",
"ppc64le-redhat-linux"};
static const char *const RISCV32LibDirs[] = {"/lib32", "/lib"};
static const char *const RISCV32Triples[] = {"riscv32-unknown-linux-gnu",
"riscv32-linux-gnu",
"riscv32-unknown-elf"};
static const char *const RISCV64LibDirs[] = {"/lib64", "/lib"};
static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu",
"riscv64-linux-gnu",
"riscv64-unknown-elf"};
static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
static const char *const SPARCv8Triples[] = {"sparc-linux-gnu",
"sparcv8-linux-gnu"};
static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"};
static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu",
"sparcv9-linux-gnu"};
static const char *const SystemZLibDirs[] = {"/lib64", "/lib"};
static const char *const SystemZTriples[] = {
"s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu",
"s390x-suse-linux", "s390x-redhat-linux"};
using std::begin;
using std::end;