[Driver] Consolidate tools and toolchains by target platform. (NFC)
Summary:
(This is a move-only refactoring patch. There are no functionality changes.)
This patch splits apart the Clang driver's tool and toolchain implementation
files. Each target platform toolchain is moved to its own file, along with the
closest-related tools. Each target platform toolchain has separate headers and
implementation files, so the hierarchy of classes is unchanged.
There are some remaining shared free functions, mostly from Tools.cpp. Several
of these move to their own architecture-specific files, similar to r296056. Some
of them are only used by a single target platform; since the tools and
toolchains are now together, some helpers now live in a platform-specific file.
The balance are helpers related to manipulating argument lists, so they are now
in a new file pair, CommonArgs.h and .cpp.
I've tried to cluster the code logically, which is fairly straightforward for
most of the target platforms and shared architectures. I think I've made
reasonable choices for these, as well as the various shared helpers; but of
course, I'm happy to hear feedback in the review.
There are some particular things I don't like about this patch, but haven't been
able to find a better overall solution. The first is the proliferation of files:
there are several files that are tiny because the toolchain is not very
different from its base (usually the Gnu tools/toolchain). I think this is
mostly a reflection of the true complexity, though, so it may not be "fixable"
in any reasonable sense. The second thing I don't like are the includes like
"../Something.h". I've avoided this largely by clustering into the current file
structure. However, a few of these includes remain, and in those cases it
doesn't make sense to me to sink an existing file any deeper.
Reviewers: rsmith, mehdi_amini, compnerd, rnk, javed.absar
Subscribers: emaste, jfb, danalbert, srhines, dschuff, jyknight, nemanjai, nhaehnle, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D30372
llvm-svn: 297250
2017-03-08 09:02:16 +08:00
|
|
|
//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "Gnu.h"
|
|
|
|
#include "Linux.h"
|
|
|
|
#include "Arch/ARM.h"
|
|
|
|
#include "Arch/Mips.h"
|
|
|
|
#include "Arch/Sparc.h"
|
|
|
|
#include "Arch/SystemZ.h"
|
|
|
|
#include "CommonArgs.h"
|
|
|
|
#include "clang/Basic/VirtualFileSystem.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 "llvm/Option/ArgList.h"
|
|
|
|
#include "llvm/Support/CodeGen.h"
|
|
|
|
#include "llvm/Support/Path.h"
|
|
|
|
#include "llvm/Support/TargetParser.h"
|
|
|
|
#include <system_error>
|
|
|
|
|
|
|
|
using namespace clang::driver;
|
|
|
|
using namespace clang::driver::toolchains;
|
|
|
|
using namespace clang;
|
|
|
|
using namespace llvm::opt;
|
|
|
|
|
|
|
|
void tools::GnuTool::anchor() {}
|
|
|
|
|
|
|
|
static bool forwardToGCC(const Option &O) {
|
|
|
|
// Don't forward inputs from the original command line. They are added from
|
|
|
|
// InputInfoList.
|
|
|
|
return O.getKind() != Option::InputClass &&
|
|
|
|
!O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput);
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
// Don't forward any -g arguments to assembly steps.
|
|
|
|
if (isa<AssembleJobAction>(JA) &&
|
|
|
|
A->getOption().matches(options::OPT_g_Group))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Don't forward any -W arguments to assembly and link steps.
|
|
|
|
if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) &&
|
|
|
|
A->getOption().matches(options::OPT_W_Group))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
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:
|
|
|
|
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(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Add OpenMP linker script arguments at the end of the argument list so that
|
|
|
|
/// the fat binary is built by embedding each of the device images into the
|
|
|
|
/// host. The linker script also defines a few symbols required by the code
|
|
|
|
/// generation so that the images can be easily retrieved at runtime by the
|
|
|
|
/// offloading library. This should be used only in tool chains that support
|
|
|
|
/// linker scripts.
|
|
|
|
static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C,
|
|
|
|
const InputInfo &Output,
|
|
|
|
const InputInfoList &Inputs,
|
|
|
|
const ArgList &Args, ArgStringList &CmdArgs,
|
|
|
|
const JobAction &JA) {
|
|
|
|
|
|
|
|
// If this is not an OpenMP host toolchain, we don't need to do anything.
|
|
|
|
if (!JA.isHostOffloading(Action::OFK_OpenMP))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Create temporary linker script. Keep it if save-temps is enabled.
|
|
|
|
const char *LKS;
|
|
|
|
SmallString<256> Name = llvm::sys::path::filename(Output.getFilename());
|
|
|
|
if (C.getDriver().isSaveTempsEnabled()) {
|
|
|
|
llvm::sys::path::replace_extension(Name, "lk");
|
|
|
|
LKS = C.getArgs().MakeArgString(Name.c_str());
|
|
|
|
} else {
|
|
|
|
llvm::sys::path::replace_extension(Name, "");
|
|
|
|
Name = C.getDriver().GetTemporaryPath(Name, "lk");
|
|
|
|
LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str()));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add linker script option to the command.
|
|
|
|
CmdArgs.push_back("-T");
|
|
|
|
CmdArgs.push_back(LKS);
|
|
|
|
|
|
|
|
// Create a buffer to write the contents of the linker script.
|
|
|
|
std::string LksBuffer;
|
|
|
|
llvm::raw_string_ostream LksStream(LksBuffer);
|
|
|
|
|
|
|
|
// Get the OpenMP offload tool chains so that we can extract the triple
|
|
|
|
// associated with each device input.
|
|
|
|
auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>();
|
|
|
|
assert(OpenMPToolChains.first != OpenMPToolChains.second &&
|
|
|
|
"No OpenMP toolchains??");
|
|
|
|
|
|
|
|
// Track the input file name and device triple in order to build the script,
|
|
|
|
// inserting binaries in the designated sections.
|
|
|
|
SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo;
|
|
|
|
|
|
|
|
// Add commands to embed target binaries. We ensure that each section and
|
|
|
|
// image is 16-byte aligned. This is not mandatory, but increases the
|
|
|
|
// likelihood of data to be aligned with a cache block in several main host
|
|
|
|
// machines.
|
|
|
|
LksStream << "/*\n";
|
|
|
|
LksStream << " OpenMP Offload Linker Script\n";
|
|
|
|
LksStream << " *** Automatically generated by Clang ***\n";
|
|
|
|
LksStream << "*/\n";
|
|
|
|
LksStream << "TARGET(binary)\n";
|
|
|
|
auto DTC = OpenMPToolChains.first;
|
|
|
|
for (auto &II : Inputs) {
|
|
|
|
const Action *A = II.getAction();
|
|
|
|
// Is this a device linking action?
|
|
|
|
if (A && isa<LinkJobAction>(A) &&
|
|
|
|
A->isDeviceOffloading(Action::OFK_OpenMP)) {
|
|
|
|
assert(DTC != OpenMPToolChains.second &&
|
|
|
|
"More device inputs than device toolchains??");
|
|
|
|
InputBinaryInfo.push_back(std::make_pair(
|
|
|
|
DTC->second->getTriple().normalize(), II.getFilename()));
|
|
|
|
++DTC;
|
|
|
|
LksStream << "INPUT(" << II.getFilename() << ")\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(DTC == OpenMPToolChains.second &&
|
|
|
|
"Less device inputs than device toolchains??");
|
|
|
|
|
|
|
|
LksStream << "SECTIONS\n";
|
|
|
|
LksStream << "{\n";
|
|
|
|
LksStream << " .omp_offloading :\n";
|
|
|
|
LksStream << " ALIGN(0x10)\n";
|
|
|
|
LksStream << " {\n";
|
|
|
|
|
|
|
|
for (auto &BI : InputBinaryInfo) {
|
|
|
|
LksStream << " . = ALIGN(0x10);\n";
|
|
|
|
LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first
|
|
|
|
<< " = .);\n";
|
|
|
|
LksStream << " " << BI.second << "\n";
|
|
|
|
LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first
|
|
|
|
<< " = .);\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
LksStream << " }\n";
|
|
|
|
// Add commands to define host entries begin and end. We use 1-byte subalign
|
|
|
|
// so that the linker does not add any padding and the elements in this
|
|
|
|
// section form an array.
|
|
|
|
LksStream << " .omp_offloading.entries :\n";
|
|
|
|
LksStream << " ALIGN(0x10)\n";
|
|
|
|
LksStream << " SUBALIGN(0x01)\n";
|
|
|
|
LksStream << " {\n";
|
|
|
|
LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n";
|
|
|
|
LksStream << " *(.omp_offloading.entries)\n";
|
|
|
|
LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n";
|
|
|
|
LksStream << " }\n";
|
|
|
|
LksStream << "}\n";
|
|
|
|
LksStream << "INSERT BEFORE .data\n";
|
|
|
|
LksStream.flush();
|
|
|
|
|
|
|
|
// Dump the contents of the linker script if the user requested that. We
|
|
|
|
// support this option to enable testing of behavior with -###.
|
|
|
|
if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script))
|
|
|
|
llvm::errs() << LksBuffer;
|
|
|
|
|
|
|
|
// If this is a dry run, do not create the linker script file.
|
|
|
|
if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Open script file and write the contents.
|
|
|
|
std::error_code EC;
|
|
|
|
llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None);
|
|
|
|
|
|
|
|
if (EC) {
|
|
|
|
C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Lksf << LksBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args,
|
|
|
|
ArgStringList &CmdArgs) {
|
|
|
|
if (Args.hasFlag(options::OPT_fxray_instrument,
|
|
|
|
options::OPT_fnoxray_instrument, false)) {
|
|
|
|
CmdArgs.push_back("-whole-archive");
|
|
|
|
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false));
|
|
|
|
CmdArgs.push_back("-no-whole-archive");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args,
|
|
|
|
ArgStringList &CmdArgs) {
|
|
|
|
CmdArgs.push_back("--no-as-needed");
|
|
|
|
CmdArgs.push_back("-lpthread");
|
|
|
|
CmdArgs.push_back("-lrt");
|
|
|
|
CmdArgs.push_back("-lm");
|
2017-03-08 20:06:44 +08:00
|
|
|
|
[Driver] Consolidate tools and toolchains by target platform. (NFC)
Summary:
(This is a move-only refactoring patch. There are no functionality changes.)
This patch splits apart the Clang driver's tool and toolchain implementation
files. Each target platform toolchain is moved to its own file, along with the
closest-related tools. Each target platform toolchain has separate headers and
implementation files, so the hierarchy of classes is unchanged.
There are some remaining shared free functions, mostly from Tools.cpp. Several
of these move to their own architecture-specific files, similar to r296056. Some
of them are only used by a single target platform; since the tools and
toolchains are now together, some helpers now live in a platform-specific file.
The balance are helpers related to manipulating argument lists, so they are now
in a new file pair, CommonArgs.h and .cpp.
I've tried to cluster the code logically, which is fairly straightforward for
most of the target platforms and shared architectures. I think I've made
reasonable choices for these, as well as the various shared helpers; but of
course, I'm happy to hear feedback in the review.
There are some particular things I don't like about this patch, but haven't been
able to find a better overall solution. The first is the proliferation of files:
there are several files that are tiny because the toolchain is not very
different from its base (usually the Gnu tools/toolchain). I think this is
mostly a reflection of the true complexity, though, so it may not be "fixable"
in any reasonable sense. The second thing I don't like are the includes like
"../Something.h". I've avoided this largely by clustering into the current file
structure. However, a few of these includes remain, and in those cases it
doesn't make sense to me to sink an existing file any deeper.
Reviewers: rsmith, mehdi_amini, compnerd, rnk, javed.absar
Subscribers: emaste, jfb, danalbert, srhines, dschuff, jyknight, nemanjai, nhaehnle, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D30372
llvm-svn: 297250
2017-03-08 09:02:16 +08:00
|
|
|
if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
|
|
|
|
CmdArgs.push_back("-ldl");
|
|
|
|
}
|
|
|
|
|
|
|
|
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 "aarch64_be_linux";
|
|
|
|
case llvm::Triple::arm:
|
|
|
|
case llvm::Triple::thumb:
|
|
|
|
return "armelf_linux_eabi";
|
|
|
|
case llvm::Triple::armeb:
|
|
|
|
case llvm::Triple::thumbeb:
|
|
|
|
return "armelfb_linux_eabi";
|
|
|
|
case llvm::Triple::ppc:
|
|
|
|
return "elf32ppclinux";
|
|
|
|
case llvm::Triple::ppc64:
|
|
|
|
return "elf64ppc";
|
|
|
|
case llvm::Triple::ppc64le:
|
|
|
|
return "elf64lppc";
|
|
|
|
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"))
|
|
|
|
return "elf32btsmipn32";
|
|
|
|
return "elf64btsmip";
|
|
|
|
case llvm::Triple::mips64el:
|
|
|
|
if (tools::mips::hasMipsAbiArg(Args, "n32"))
|
|
|
|
return "elf32ltsmipn32";
|
|
|
|
return "elf64ltsmip";
|
|
|
|
case llvm::Triple::systemz:
|
|
|
|
return "elf64_s390";
|
|
|
|
case llvm::Triple::x86_64:
|
|
|
|
if (T.getEnvironment() == llvm::Triple::GNUX32)
|
|
|
|
return "elf32_x86_64";
|
|
|
|
return "elf_x86_64";
|
|
|
|
default:
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
|
|
|
|
const InputInfo &Output,
|
|
|
|
const InputInfoList &Inputs,
|
|
|
|
const ArgList &Args,
|
|
|
|
const char *LinkingOutput) const {
|
|
|
|
const toolchains::Linux &ToolChain =
|
|
|
|
static_cast<const toolchains::Linux &>(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 IsPIE =
|
|
|
|
!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) &&
|
|
|
|
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
|
|
|
|
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);
|
|
|
|
|
|
|
|
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
|
|
|
|
if (llvm::sys::path::stem(Exec) == "lld") {
|
|
|
|
CmdArgs.push_back("-flavor");
|
|
|
|
CmdArgs.push_back("old-gnu");
|
|
|
|
CmdArgs.push_back("-target");
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString()));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!D.SysRoot.empty())
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
|
|
|
|
|
|
|
|
if (IsPIE)
|
|
|
|
CmdArgs.push_back("-pie");
|
|
|
|
|
|
|
|
if (Args.hasArg(options::OPT_rdynamic))
|
|
|
|
CmdArgs.push_back("-export-dynamic");
|
|
|
|
|
|
|
|
if (Args.hasArg(options::OPT_s))
|
|
|
|
CmdArgs.push_back("-s");
|
|
|
|
|
|
|
|
if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb)
|
|
|
|
arm::appendEBLinkFlags(Args, CmdArgs, Triple);
|
|
|
|
|
|
|
|
// 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(Args, Triple);
|
|
|
|
if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53")
|
|
|
|
CmdArgs.push_back("--fix-cortex-a53-843419");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &Opt : ToolChain.ExtraOpts)
|
|
|
|
CmdArgs.push_back(Opt.c_str());
|
|
|
|
|
|
|
|
if (!Args.hasArg(options::OPT_static)) {
|
|
|
|
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 (Args.hasArg(options::OPT_static)) {
|
|
|
|
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
|
|
|
|
Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb)
|
|
|
|
CmdArgs.push_back("-Bstatic");
|
|
|
|
else
|
|
|
|
CmdArgs.push_back("-static");
|
|
|
|
} else if (Args.hasArg(options::OPT_shared)) {
|
|
|
|
CmdArgs.push_back("-shared");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Args.hasArg(options::OPT_static)) {
|
|
|
|
if (Args.hasArg(options::OPT_rdynamic))
|
|
|
|
CmdArgs.push_back("-export-dynamic");
|
|
|
|
|
|
|
|
if (!Args.hasArg(options::OPT_shared)) {
|
|
|
|
const std::string Loader =
|
|
|
|
D.DyldPrefix + ToolChain.getDynamicLinker(Args);
|
|
|
|
CmdArgs.push_back("-dynamic-linker");
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(Loader));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CmdArgs.push_back("-o");
|
|
|
|
CmdArgs.push_back(Output.getFilename());
|
|
|
|
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
|
|
|
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
|
|
|
|
crt1 = "crt1.o";
|
|
|
|
}
|
|
|
|
if (crt1)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1)));
|
|
|
|
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsIAMCU)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
|
|
|
|
else {
|
|
|
|
const char *crtbegin;
|
|
|
|
if (Args.hasArg(options::OPT_static))
|
|
|
|
crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o";
|
|
|
|
else if (Args.hasArg(options::OPT_shared))
|
|
|
|
crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o";
|
|
|
|
else if (IsPIE)
|
|
|
|
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o";
|
|
|
|
else
|
|
|
|
crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o";
|
|
|
|
|
|
|
|
if (HasCRTBeginEndFiles)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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())
|
|
|
|
AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D);
|
|
|
|
|
|
|
|
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);
|
|
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
|
|
|
|
// The profile runtime also needs access to system libraries.
|
|
|
|
getToolChain().addProfileRTLibs(Args, CmdArgs);
|
|
|
|
|
|
|
|
if (D.CCCIsCXX() &&
|
|
|
|
!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
// Silence warnings when linking C code with a C++ '-stdlib' argument.
|
|
|
|
Args.ClaimAllArgs(options::OPT_stdlib_EQ);
|
|
|
|
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib)) {
|
|
|
|
if (!Args.hasArg(options::OPT_nodefaultlibs)) {
|
|
|
|
if (Args.hasArg(options::OPT_static))
|
|
|
|
CmdArgs.push_back("--start-group");
|
|
|
|
|
|
|
|
if (NeedsSanitizerDeps)
|
|
|
|
linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
|
|
|
|
|
|
|
|
if (NeedsXRayDeps)
|
|
|
|
linkXRayRuntimeDeps(ToolChain, Args, CmdArgs);
|
|
|
|
|
|
|
|
bool WantPthread = Args.hasArg(options::OPT_pthread) ||
|
|
|
|
Args.hasArg(options::OPT_pthreads);
|
|
|
|
|
|
|
|
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
|
|
|
options::OPT_fno_openmp, false)) {
|
|
|
|
// OpenMP runtimes implies pthreads when using the GNU toolchain.
|
|
|
|
// FIXME: Does this really make sense for all GNU toolchains?
|
|
|
|
WantPthread = true;
|
|
|
|
|
|
|
|
// Also link the particular OpenMP runtimes.
|
|
|
|
switch (ToolChain.getDriver().getOpenMPRuntime(Args)) {
|
|
|
|
case Driver::OMPRT_OMP:
|
|
|
|
CmdArgs.push_back("-lomp");
|
|
|
|
break;
|
|
|
|
case Driver::OMPRT_GOMP:
|
|
|
|
CmdArgs.push_back("-lgomp");
|
|
|
|
|
|
|
|
// FIXME: Exclude this for platforms with libgomp that don't require
|
|
|
|
// librt. Most modern Linux platforms require it, but some may not.
|
|
|
|
CmdArgs.push_back("-lrt");
|
|
|
|
break;
|
|
|
|
case Driver::OMPRT_IOMP5:
|
|
|
|
CmdArgs.push_back("-liomp5");
|
|
|
|
break;
|
|
|
|
case Driver::OMPRT_Unknown:
|
|
|
|
// Already diagnosed.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (JA.isHostOffloading(Action::OFK_OpenMP))
|
|
|
|
CmdArgs.push_back("-lomptarget");
|
|
|
|
|
|
|
|
addArchSpecificRPath(ToolChain, Args, CmdArgs);
|
|
|
|
}
|
|
|
|
|
|
|
|
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
|
|
|
|
|
|
|
|
if (WantPthread && !isAndroid)
|
|
|
|
CmdArgs.push_back("-lpthread");
|
|
|
|
|
|
|
|
if (Args.hasArg(options::OPT_fsplit_stack))
|
|
|
|
CmdArgs.push_back("--wrap=pthread_create");
|
|
|
|
|
|
|
|
CmdArgs.push_back("-lc");
|
|
|
|
|
|
|
|
// Add IAMCU specific libs, if needed.
|
|
|
|
if (IsIAMCU)
|
|
|
|
CmdArgs.push_back("-lgloss");
|
|
|
|
|
|
|
|
if (Args.hasArg(options::OPT_static))
|
|
|
|
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) {
|
|
|
|
const char *crtend;
|
|
|
|
if (Args.hasArg(options::OPT_shared))
|
|
|
|
crtend = isAndroid ? "crtend_so.o" : "crtendS.o";
|
|
|
|
else if (IsPIE)
|
|
|
|
crtend = isAndroid ? "crtend_android.o" : "crtendS.o";
|
|
|
|
else
|
|
|
|
crtend = isAndroid ? "crtend_android.o" : "crtend.o";
|
|
|
|
|
|
|
|
if (HasCRTBeginEndFiles)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend)));
|
|
|
|
if (!isAndroid)
|
|
|
|
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add OpenMP offloading linker script args if required.
|
|
|
|
AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA);
|
|
|
|
|
|
|
|
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
|
|
|
}
|
|
|
|
|
|
|
|
void tools::gnutools::Assembler::ConstructJob(Compilation &C,
|
|
|
|
const JobAction &JA,
|
|
|
|
const InputInfo &Output,
|
|
|
|
const InputInfoList &Inputs,
|
|
|
|
const ArgList &Args,
|
|
|
|
const char *LinkingOutput) const {
|
|
|
|
claimNoWarnArgs(Args);
|
|
|
|
|
|
|
|
ArgStringList CmdArgs;
|
|
|
|
|
|
|
|
llvm::Reloc::Model RelocationModel;
|
|
|
|
unsigned PICLevel;
|
|
|
|
bool IsPIE;
|
|
|
|
std::tie(RelocationModel, PICLevel, IsPIE) =
|
|
|
|
ParsePICArgs(getToolChain(), Args);
|
|
|
|
|
|
|
|
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().getEnvironment() == llvm::Triple::GNUX32)
|
|
|
|
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("-many");
|
|
|
|
break;
|
|
|
|
case llvm::Triple::ppc64:
|
|
|
|
CmdArgs.push_back("-a64");
|
|
|
|
CmdArgs.push_back("-mppc64");
|
|
|
|
CmdArgs.push_back("-many");
|
|
|
|
break;
|
|
|
|
case llvm::Triple::ppc64le:
|
|
|
|
CmdArgs.push_back("-a64");
|
|
|
|
CmdArgs.push_back("-mppc64");
|
|
|
|
CmdArgs.push_back("-many");
|
|
|
|
CmdArgs.push_back("-mlittle-endian");
|
|
|
|
break;
|
|
|
|
case llvm::Triple::sparc:
|
|
|
|
case llvm::Triple::sparcel: {
|
|
|
|
CmdArgs.push_back("-32");
|
|
|
|
std::string CPU = getCPUName(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(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();
|
|
|
|
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);
|
|
|
|
|
|
|
|
// FIXME: remove krait check when GNU tools support krait cpu
|
|
|
|
// for now replace it with -mcpu=cortex-a15 to avoid a lower
|
|
|
|
// march from being picked in the absence of a cpu flag.
|
|
|
|
Arg *A;
|
|
|
|
if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) &&
|
|
|
|
StringRef(A->getValue()).equals_lower("krait"))
|
|
|
|
CmdArgs.push_back("-mcpu=cortex-a15");
|
|
|
|
else
|
|
|
|
Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ);
|
|
|
|
Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ);
|
|
|
|
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().getArch() == llvm::Triple::mips ||
|
|
|
|
getToolChain().getArch() == llvm::Triple::mips64)
|
|
|
|
CmdArgs.push_back("-EB");
|
|
|
|
else
|
|
|
|
CmdArgs.push_back("-EL");
|
|
|
|
|
|
|
|
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)))
|
|
|
|
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.
|
|
|
|
StringRef CPUName = systemz::getSystemZTargetCPU(Args);
|
|
|
|
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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("as"));
|
|
|
|
C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
|
|
|
|
|
|
|
|
// 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(Args, Inputs[0]));
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
// Filter to remove Multilibs that don't exist as a suffix to Path
|
|
|
|
class FilterNonExistent {
|
|
|
|
StringRef Base, File;
|
|
|
|
vfs::FileSystem &VFS;
|
|
|
|
|
|
|
|
public:
|
|
|
|
FilterNonExistent(StringRef Base, StringRef File, 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 void addMultilibFlag(bool Enabled, const char *const Flag,
|
|
|
|
std::vector<std::string> &Flags) {
|
|
|
|
if (Enabled)
|
|
|
|
Flags.push_back(std::string("+") + Flag);
|
|
|
|
else
|
|
|
|
Flags.push_back(std::string("-") + Flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) {
|
|
|
|
return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isMips32(llvm::Triple::ArchType Arch) {
|
|
|
|
return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool isMips64(llvm::Triple::ArchType Arch) {
|
|
|
|
return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el;
|
|
|
|
}
|
|
|
|
|
|
|
|
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 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().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(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(isMips32(TargetArch), "m32", Flags);
|
|
|
|
addMultilibFlag(isMips64(TargetArch), "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",
|
|
|
|
"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(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.getEnvironment() == llvm::Triple::GNU)
|
|
|
|
return findMipsMtiMultilibs(Flags, NonExistent, Result);
|
|
|
|
|
|
|
|
if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies &&
|
|
|
|
TargetTriple.getOS() == llvm::Triple::Linux &&
|
|
|
|
TargetTriple.getEnvironment() == llvm::Triple::GNU)
|
|
|
|
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("+armv7")
|
|
|
|
.flag("-thumb");
|
|
|
|
Multilib ThumbMultilib = makeMultilib("/thumb")
|
|
|
|
.flag("-armv7")
|
|
|
|
.flag("+thumb");
|
|
|
|
Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb")
|
|
|
|
.flag("+armv7")
|
|
|
|
.flag("+thumb");
|
|
|
|
Multilib DefaultMultilib = makeMultilib("")
|
|
|
|
.flag("-armv7")
|
|
|
|
.flag("-thumb");
|
|
|
|
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::IK_THUMB);
|
|
|
|
bool IsArmV7Mode = (IsArmArch || IsThumbArch) &&
|
|
|
|
(llvm::ARM::parseArchVersion(Arch) == 7 ||
|
|
|
|
(IsArmArch && Arch == "" && IsV7SubArch));
|
|
|
|
addMultilibFlag(IsArmV7Mode, "armv7", Flags);
|
|
|
|
addMultilibFlag(IsThumbMode, "thumb", Flags);
|
|
|
|
|
|
|
|
if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
|
|
|
|
Result.Multilibs = AndroidArmMultilibs;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool findBiarchMultilibs(const Driver &D,
|
|
|
|
const llvm::Triple &TargetTriple,
|
|
|
|
StringRef Path, const ArgList &Args,
|
|
|
|
bool NeedsBiarchSuffix,
|
|
|
|
DetectedMultilibs &Result) {
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
Multilib Default;
|
|
|
|
Multilib Alt64 = Multilib()
|
|
|
|
.gccSuffix("/64")
|
|
|
|
.includeSuffix("/64")
|
|
|
|
.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.getEnvironment() == llvm::Triple::GNUX32;
|
|
|
|
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.
|
|
|
|
|
|
|
|
/// \brief 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static llvm::StringRef getGCCToolchainDir(const ArgList &Args) {
|
|
|
|
const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain);
|
|
|
|
if (A)
|
|
|
|
return A->getValue();
|
|
|
|
return GCC_INSTALL_PREFIX;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief 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(D.PrefixDirs.begin(),
|
|
|
|
D.PrefixDirs.end());
|
|
|
|
|
|
|
|
StringRef GCCToolchainDir = getGCCToolchainDir(Args);
|
|
|
|
if (GCCToolchainDir != "") {
|
|
|
|
if (GCCToolchainDir.back() == '/')
|
|
|
|
GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
|
|
|
|
|
|
|
|
Prefixes.push_back(GCCToolchainDir);
|
|
|
|
} else {
|
|
|
|
// If we have a SysRoot, try that first.
|
|
|
|
if (!D.SysRoot.empty()) {
|
|
|
|
Prefixes.push_back(D.SysRoot);
|
|
|
|
Prefixes.push_back(D.SysRoot + "/usr");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Then look for gcc installed alongside clang.
|
|
|
|
Prefixes.push_back(D.InstalledDir + "/..");
|
|
|
|
|
|
|
|
// Then look for distribution supplied gcc installations.
|
|
|
|
if (D.SysRoot.empty()) {
|
|
|
|
// Look for RHEL devtoolsets.
|
|
|
|
Prefixes.push_back("/opt/rh/devtoolset-6/root/usr");
|
|
|
|
Prefixes.push_back("/opt/rh/devtoolset-4/root/usr");
|
|
|
|
Prefixes.push_back("/opt/rh/devtoolset-3/root/usr");
|
|
|
|
Prefixes.push_back("/opt/rh/devtoolset-2/root/usr");
|
|
|
|
// And finally in /usr.
|
|
|
|
Prefixes.push_back("/usr");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try to respect gcc-config on Gentoo. However, do that only
|
|
|
|
// if --gcc-toolchain is not provided or equal to the Gentoo install
|
|
|
|
// in /usr. This avoids accidentally enforcing the system GCC version
|
|
|
|
// when using a custom toolchain.
|
|
|
|
if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") {
|
|
|
|
for (StringRef CandidateTriple : ExtraTripleAliases) {
|
|
|
|
if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (StringRef CandidateTriple : CandidateTripleAliases) {
|
|
|
|
if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for (StringRef CandidateTriple : CandidateBiarchTripleAliases) {
|
|
|
|
if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Loop over the various components which exist and select the best GCC
|
|
|
|
// installation available. GCC installs are ranked by version number.
|
|
|
|
Version = GCCVersion::Parse("0.0.0");
|
|
|
|
for (const std::string &Prefix : Prefixes) {
|
|
|
|
if (!D.getVFS().exists(Prefix))
|
|
|
|
continue;
|
|
|
|
for (StringRef Suffix : CandidateLibDirs) {
|
|
|
|
const std::string LibDir = Prefix + Suffix.str();
|
|
|
|
if (!D.getVFS().exists(LibDir))
|
|
|
|
continue;
|
|
|
|
for (StringRef Candidate : ExtraTripleAliases) // Try these first.
|
|
|
|
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
|
|
|
|
for (StringRef Candidate : CandidateTripleAliases)
|
|
|
|
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate);
|
|
|
|
}
|
|
|
|
for (StringRef Suffix : CandidateBiarchLibDirs) {
|
|
|
|
const std::string LibDir = Prefix + Suffix.str();
|
|
|
|
if (!D.getVFS().exists(LibDir))
|
|
|
|
continue;
|
|
|
|
for (StringRef Candidate : CandidateBiarchTripleAliases)
|
|
|
|
ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate,
|
|
|
|
/*NeedsBiarchSuffix=*/ true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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.hasValue()) {
|
|
|
|
M = BiarchSibling.getValue();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*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.
|
|
|
|
static const char *const AArch64LibDirs[] = {"/lib64", "/lib"};
|
|
|
|
static const char *const AArch64Triples[] = {
|
|
|
|
"aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android",
|
|
|
|
"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",
|
|
|
|
"arm-linux-androideabi"};
|
|
|
|
static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf",
|
|
|
|
"armv7hl-redhat-linux-gnueabi"};
|
|
|
|
static const char *const ARMebLibDirs[] = {"/lib"};
|
|
|
|
static const char *const ARMebTriples[] = {"armeb-linux-gnueabi",
|
|
|
|
"armeb-linux-androideabi"};
|
|
|
|
static const char *const ARMebHFTriples[] = {
|
|
|
|
"armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"};
|
|
|
|
|
|
|
|
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-linux-android",
|
|
|
|
"x86_64-unknown-linux"};
|
|
|
|
static const char *const X32LibDirs[] = {"/libx32"};
|
|
|
|
static const char *const X86LibDirs[] = {"/lib32", "/lib"};
|
|
|
|
static const char *const X86Triples[] = {
|
|
|
|
"i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu",
|
|
|
|
"i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux",
|
|
|
|
"i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux",
|
|
|
|
"i486-slackware-linux", "i686-montavista-linux", "i686-linux-android",
|
|
|
|
"i586-linux-gnu"};
|
|
|
|
|
|
|
|
static const char *const MIPSLibDirs[] = {"/lib"};
|
|
|
|
static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux",
|
|
|
|
"mips-mti-linux-gnu",
|
|
|
|
"mips-img-linux-gnu"};
|
|
|
|
static const char *const MIPSELLibDirs[] = {"/lib"};
|
|
|
|
static const char *const MIPSELTriples[] = {"mipsel-linux-gnu",
|
|
|
|
"mips-img-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"};
|
|
|
|
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"};
|
|
|
|
|
|
|
|
static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2",
|
|
|
|
"/libr6"};
|
|
|
|
static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"};
|
|
|
|
static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib",
|
|
|
|
"/libr2", "/libr6"};
|
|
|
|
static const char *const MIPS64ELAndroidTriples[] = {
|
|
|
|
"mips64el-linux-android"};
|
|
|
|
|
|
|
|
static const char *const PPCLibDirs[] = {"/lib32", "/lib"};
|
|
|
|
static const char *const PPCTriples[] = {
|
|
|
|
"powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe",
|
|
|
|
"powerpc-suse-linux", "powerpc-montavista-linuxspe"};
|
|
|
|
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-suse-linux", "ppc64le-redhat-linux"};
|
|
|
|
|
|
|
|
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"};
|
|
|
|
|
|
|
|
// Solaris.
|
|
|
|
static const char *const SolarisSPARCLibDirs[] = {"/gcc"};
|
|
|
|
static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11",
|
|
|
|
"i386-pc-solaris2.11"};
|
|
|
|
|
|
|
|
using std::begin;
|
|
|
|
using std::end;
|
|
|
|
|
|
|
|
if (TargetTriple.getOS() == llvm::Triple::Solaris) {
|
|
|
|
LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs));
|
|
|
|
TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (TargetTriple.getArch()) {
|
|
|
|
case llvm::Triple::aarch64:
|
|
|
|
LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
|
|
|
|
TripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
|
|
|
|
BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::aarch64_be:
|
|
|
|
LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
|
|
|
|
TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
|
|
|
|
BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::arm:
|
|
|
|
case llvm::Triple::thumb:
|
|
|
|
LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs));
|
|
|
|
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
|
|
|
|
TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples));
|
|
|
|
} else {
|
|
|
|
TripleAliases.append(begin(ARMTriples), end(ARMTriples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::armeb:
|
|
|
|
case llvm::Triple::thumbeb:
|
|
|
|
LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs));
|
|
|
|
if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) {
|
|
|
|
TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples));
|
|
|
|
} else {
|
|
|
|
TripleAliases.append(begin(ARMebTriples), end(ARMebTriples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::x86_64:
|
|
|
|
LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
|
|
|
|
TripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
|
|
|
|
// x32 is always available when x86_64 is available, so adding it as
|
|
|
|
// secondary arch with x86_64 triples
|
|
|
|
if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) {
|
|
|
|
BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
|
|
|
|
} else {
|
|
|
|
BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(X86Triples), end(X86Triples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::x86:
|
|
|
|
LibDirs.append(begin(X86LibDirs), end(X86LibDirs));
|
|
|
|
// MCU toolchain is 32 bit only and its triple alias is TargetTriple
|
|
|
|
// itself, which will be appended below.
|
|
|
|
if (!TargetTriple.isOSIAMCU()) {
|
|
|
|
TripleAliases.append(begin(X86Triples), end(X86Triples));
|
|
|
|
BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::mips:
|
|
|
|
LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
|
|
|
|
TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
|
|
|
|
BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::mipsel:
|
|
|
|
if (TargetTriple.isAndroid()) {
|
|
|
|
LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs));
|
|
|
|
TripleAliases.append(begin(MIPSELAndroidTriples),
|
|
|
|
end(MIPSELAndroidTriples));
|
|
|
|
BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs),
|
|
|
|
end(MIPS64ELAndroidLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples),
|
|
|
|
end(MIPS64ELAndroidTriples));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
|
|
|
|
TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
|
|
|
|
TripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
|
|
|
|
BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::mips64:
|
|
|
|
LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs));
|
|
|
|
TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples));
|
|
|
|
BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::mips64el:
|
|
|
|
if (TargetTriple.isAndroid()) {
|
|
|
|
LibDirs.append(begin(MIPS64ELAndroidLibDirs),
|
|
|
|
end(MIPS64ELAndroidLibDirs));
|
|
|
|
TripleAliases.append(begin(MIPS64ELAndroidTriples),
|
|
|
|
end(MIPS64ELAndroidTriples));
|
|
|
|
BiarchLibDirs.append(begin(MIPSELAndroidLibDirs),
|
|
|
|
end(MIPSELAndroidLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPSELAndroidTriples),
|
|
|
|
end(MIPSELAndroidTriples));
|
|
|
|
|
|
|
|
} else {
|
|
|
|
LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs));
|
|
|
|
TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples));
|
|
|
|
BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples));
|
|
|
|
BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case llvm::Triple::ppc:
|
|
|
|
LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
|
|
|
|
TripleAliases.append(begin(PPCTriples), end(PPCTriples));
|
|
|
|
BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::ppc64:
|
|
|
|
LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs));
|
|
|
|
TripleAliases.append(begin(PPC64Triples), end(PPC64Triples));
|
|
|
|
BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::ppc64le:
|
|
|
|
LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs));
|
|
|
|
TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::sparc:
|
|
|
|
case llvm::Triple::sparcel:
|
|
|
|
LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
|
|
|
|
TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
|
|
|
|
BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::sparcv9:
|
|
|
|
LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs));
|
|
|
|
TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples));
|
|
|
|
BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs));
|
|
|
|
BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples));
|
|
|
|
break;
|
|
|
|
case llvm::Triple::systemz:
|
|
|
|
LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs));
|
|
|
|
TripleAliases.append(begin(SystemZTriples), end(SystemZTriples));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// By default, just rely on the standard lib directories and the original
|
|
|
|
// triple.
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always append the drivers target triple to the end, in case it doesn't
|
|
|
|
// match any of our aliases.
|
|
|
|
TripleAliases.push_back(TargetTriple.str());
|
|
|
|
|
|
|
|
// Also include the multiarch variant if it's different.
|
|
|
|
if (TargetTriple.str() != BiarchTriple.str())
|
|
|
|
BiarchTripleAliases.push_back(BiarchTriple.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris(
|
|
|
|
const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args,
|
|
|
|
const std::string &LibDir, StringRef CandidateTriple,
|
|
|
|
bool NeedsBiarchSuffix) {
|
|
|
|
// Solaris is a special case. The GCC installation is under
|
|
|
|
// /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we
|
|
|
|
// need to iterate twice.
|
|
|
|
std::error_code EC;
|
|
|
|
for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE;
|
|
|
|
!EC && LI != LE; LI = LI.increment(EC)) {
|
|
|
|
StringRef VersionText = llvm::sys::path::filename(LI->getName());
|
|
|
|
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
|
|
|
|
|
|
|
|
if (CandidateVersion.Major != -1) // Filter obviously bad entries.
|
|
|
|
if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
|
|
|
|
continue; // Saw this path before; no need to look at it again.
|
|
|
|
if (CandidateVersion.isOlderThan(4, 1, 1))
|
|
|
|
continue;
|
|
|
|
if (CandidateVersion <= Version)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GCCInstallPath =
|
|
|
|
LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str();
|
|
|
|
if (!D.getVFS().exists(GCCInstallPath))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// If we make it here there has to be at least one GCC version, let's just
|
|
|
|
// use the latest one.
|
|
|
|
std::error_code EEC;
|
|
|
|
for (vfs::directory_iterator
|
|
|
|
LLI = D.getVFS().dir_begin(GCCInstallPath, EEC),
|
|
|
|
LLE;
|
|
|
|
!EEC && LLI != LLE; LLI = LLI.increment(EEC)) {
|
|
|
|
|
|
|
|
StringRef SubVersionText = llvm::sys::path::filename(LLI->getName());
|
|
|
|
GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText);
|
|
|
|
|
|
|
|
if (CandidateSubVersion > Version)
|
|
|
|
Version = CandidateSubVersion;
|
|
|
|
}
|
|
|
|
|
|
|
|
GCCTriple.setTriple(CandidateTriple);
|
|
|
|
|
|
|
|
GCCInstallPath += "/" + Version.Text;
|
|
|
|
GCCParentLibPath = GCCInstallPath + "/../../../../";
|
|
|
|
|
|
|
|
IsValid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
|
|
|
|
const llvm::Triple &TargetTriple, const ArgList &Args,
|
|
|
|
StringRef Path, bool NeedsBiarchSuffix) {
|
|
|
|
llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
|
|
|
|
DetectedMultilibs Detected;
|
|
|
|
|
|
|
|
// Android standalone toolchain could have multilibs for ARM and Thumb.
|
|
|
|
// Debian mips multilibs behave more like the rest of the biarch ones,
|
|
|
|
// so handle them there
|
|
|
|
if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) {
|
|
|
|
// It should also work without multilibs in a simplified toolchain.
|
|
|
|
findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected);
|
|
|
|
} else if (tools::isMipsArch(TargetArch)) {
|
|
|
|
if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected))
|
|
|
|
return false;
|
|
|
|
} else if (!findBiarchMultilibs(D, TargetTriple, Path, Args,
|
|
|
|
NeedsBiarchSuffix, Detected)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Multilibs = Detected.Multilibs;
|
|
|
|
SelectedMultilib = Detected.SelectedMultilib;
|
|
|
|
BiarchSibling = Detected.BiarchSibling;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
|
|
|
|
const llvm::Triple &TargetTriple, const ArgList &Args,
|
|
|
|
const std::string &LibDir, StringRef CandidateTriple,
|
|
|
|
bool NeedsBiarchSuffix) {
|
|
|
|
if (TargetTriple.getOS() == llvm::Triple::Solaris) {
|
|
|
|
scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple,
|
|
|
|
NeedsBiarchSuffix);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
|
|
|
|
// Locations relative to the system lib directory where GCC's triple-specific
|
|
|
|
// directories might reside.
|
|
|
|
struct GCCLibSuffix {
|
|
|
|
// Path from system lib directory to GCC triple-specific directory.
|
|
|
|
std::string LibSuffix;
|
|
|
|
// Path from GCC triple-specific directory back to system lib directory.
|
|
|
|
// This is one '..' component per component in LibSuffix.
|
|
|
|
StringRef ReversePath;
|
|
|
|
// Whether this library suffix is relevant for the triple.
|
|
|
|
bool Active;
|
|
|
|
} Suffixes[] = {
|
|
|
|
// This is the normal place.
|
|
|
|
{"gcc/" + CandidateTriple.str(), "../..", true},
|
|
|
|
|
|
|
|
// Debian puts cross-compilers in gcc-cross.
|
|
|
|
{"gcc-cross/" + CandidateTriple.str(), "../..", true},
|
|
|
|
|
|
|
|
// The Freescale PPC SDK has the gcc libraries in
|
|
|
|
// <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do
|
|
|
|
// this on Freescale triples, though, since some systems put a *lot* of
|
|
|
|
// files in that location, not just GCC installation data.
|
|
|
|
{CandidateTriple.str(), "..",
|
|
|
|
TargetTriple.getVendor() == llvm::Triple::Freescale},
|
|
|
|
|
|
|
|
// Natively multiarch systems sometimes put the GCC triple-specific
|
|
|
|
// directory within their multiarch lib directory, resulting in the
|
|
|
|
// triple appearing twice.
|
|
|
|
{CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true},
|
|
|
|
|
|
|
|
// Deal with cases (on Ubuntu) where the system architecture could be i386
|
|
|
|
// but the GCC target architecture could be (say) i686.
|
|
|
|
// FIXME: It may be worthwhile to generalize this and look for a second
|
|
|
|
// triple.
|
|
|
|
{"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..",
|
|
|
|
TargetArch == llvm::Triple::x86}
|
|
|
|
};
|
|
|
|
|
|
|
|
for (auto &Suffix : Suffixes) {
|
|
|
|
if (!Suffix.Active)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
StringRef LibSuffix = Suffix.LibSuffix;
|
|
|
|
std::error_code EC;
|
|
|
|
for (vfs::directory_iterator
|
|
|
|
LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC),
|
|
|
|
LE;
|
|
|
|
!EC && LI != LE; LI = LI.increment(EC)) {
|
|
|
|
StringRef VersionText = llvm::sys::path::filename(LI->getName());
|
|
|
|
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
|
|
|
|
if (CandidateVersion.Major != -1) // Filter obviously bad entries.
|
|
|
|
if (!CandidateGCCInstallPaths.insert(LI->getName()).second)
|
|
|
|
continue; // Saw this path before; no need to look at it again.
|
|
|
|
if (CandidateVersion.isOlderThan(4, 1, 1))
|
|
|
|
continue;
|
|
|
|
if (CandidateVersion <= Version)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(),
|
|
|
|
NeedsBiarchSuffix))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
Version = CandidateVersion;
|
|
|
|
GCCTriple.setTriple(CandidateTriple);
|
|
|
|
// FIXME: We hack together the directory name here instead of
|
|
|
|
// using LI to ensure stable path separators across Windows and
|
|
|
|
// Linux.
|
|
|
|
GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str();
|
|
|
|
GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str();
|
|
|
|
IsValid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
|
|
|
|
const llvm::Triple &TargetTriple, const ArgList &Args,
|
|
|
|
StringRef CandidateTriple, bool NeedsBiarchSuffix) {
|
|
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
|
|
|
|
D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" +
|
|
|
|
CandidateTriple.str());
|
|
|
|
if (File) {
|
|
|
|
SmallVector<StringRef, 2> Lines;
|
|
|
|
File.get()->getBuffer().split(Lines, "\n");
|
|
|
|
for (StringRef Line : Lines) {
|
|
|
|
// CURRENT=triple-version
|
|
|
|
if (Line.consume_front("CURRENT=")) {
|
|
|
|
const std::pair<StringRef, StringRef> ActiveVersion =
|
|
|
|
Line.rsplit('-');
|
|
|
|
// Note: Strictly speaking, we should be reading
|
|
|
|
// /etc/env.d/gcc/${CURRENT} now. However, the file doesn't
|
|
|
|
// contain anything new or especially useful to us.
|
|
|
|
const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" +
|
|
|
|
ActiveVersion.first.str() + "/" +
|
|
|
|
ActiveVersion.second.str();
|
|
|
|
if (D.getVFS().exists(GentooPath + "/crtbegin.o")) {
|
|
|
|
if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath,
|
|
|
|
NeedsBiarchSuffix))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
Version = GCCVersion::Parse(ActiveVersion.second);
|
|
|
|
GCCInstallPath = GentooPath;
|
|
|
|
GCCParentLibPath = GentooPath + "/../../..";
|
|
|
|
GCCTriple.setTriple(ActiveVersion.first);
|
|
|
|
IsValid = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
|
|
|
|
const ArgList &Args)
|
|
|
|
: ToolChain(D, Triple, Args), GCCInstallation(D),
|
|
|
|
CudaInstallation(D, Triple, Args) {
|
|
|
|
getProgramPaths().push_back(getDriver().getInstalledDir());
|
|
|
|
if (getDriver().getInstalledDir() != getDriver().Dir)
|
|
|
|
getProgramPaths().push_back(getDriver().Dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
Generic_GCC::~Generic_GCC() {}
|
|
|
|
|
|
|
|
Tool *Generic_GCC::getTool(Action::ActionClass AC) const {
|
|
|
|
switch (AC) {
|
|
|
|
case Action::PreprocessJobClass:
|
|
|
|
if (!Preprocess)
|
|
|
|
Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this));
|
|
|
|
return Preprocess.get();
|
|
|
|
case Action::CompileJobClass:
|
|
|
|
if (!Compile)
|
|
|
|
Compile.reset(new tools::gcc::Compiler(*this));
|
|
|
|
return Compile.get();
|
|
|
|
default:
|
|
|
|
return ToolChain::getTool(AC);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Tool *Generic_GCC::buildAssembler() const {
|
|
|
|
return new tools::gnutools::Assembler(*this);
|
|
|
|
}
|
|
|
|
|
|
|
|
Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); }
|
|
|
|
|
|
|
|
void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
|
|
|
|
// Print the information about how we detected the GCC installation.
|
|
|
|
GCCInstallation.print(OS);
|
|
|
|
CudaInstallation.print(OS);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::IsUnwindTablesDefault() const {
|
|
|
|
return getArch() == llvm::Triple::x86_64;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::isPICDefault() const {
|
|
|
|
switch (getArch()) {
|
|
|
|
case llvm::Triple::x86_64:
|
|
|
|
return getTriple().isOSWindows();
|
|
|
|
case llvm::Triple::ppc64:
|
|
|
|
case llvm::Triple::ppc64le:
|
|
|
|
return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX();
|
|
|
|
case llvm::Triple::mips64:
|
|
|
|
case llvm::Triple::mips64el:
|
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::isPIEDefault() const { return false; }
|
|
|
|
|
|
|
|
bool Generic_GCC::isPICDefaultForced() const {
|
|
|
|
return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Generic_GCC::IsIntegratedAssemblerDefault() const {
|
|
|
|
switch (getTriple().getArch()) {
|
|
|
|
case llvm::Triple::x86:
|
|
|
|
case llvm::Triple::x86_64:
|
|
|
|
case llvm::Triple::aarch64:
|
|
|
|
case llvm::Triple::aarch64_be:
|
|
|
|
case llvm::Triple::arm:
|
|
|
|
case llvm::Triple::armeb:
|
|
|
|
case llvm::Triple::avr:
|
|
|
|
case llvm::Triple::bpfel:
|
|
|
|
case llvm::Triple::bpfeb:
|
|
|
|
case llvm::Triple::thumb:
|
|
|
|
case llvm::Triple::thumbeb:
|
|
|
|
case llvm::Triple::ppc:
|
|
|
|
case llvm::Triple::ppc64:
|
|
|
|
case llvm::Triple::ppc64le:
|
|
|
|
case llvm::Triple::systemz:
|
|
|
|
case llvm::Triple::mips:
|
|
|
|
case llvm::Triple::mipsel:
|
|
|
|
return true;
|
|
|
|
case llvm::Triple::mips64:
|
|
|
|
case llvm::Triple::mips64el:
|
|
|
|
// Enabled for Debian mips64/mips64el only. Other targets are unable to
|
|
|
|
// distinguish N32 from N64.
|
|
|
|
if (getTriple().getEnvironment() == llvm::Triple::GNUABI64)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
|
|
|
|
ArgStringList &CC1Args) const {
|
|
|
|
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
|
|
|
|
DriverArgs.hasArg(options::OPT_nostdincxx))
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (GetCXXStdlibType(DriverArgs)) {
|
|
|
|
case ToolChain::CST_Libcxx: {
|
|
|
|
std::string Path = findLibCxxIncludePath();
|
|
|
|
if (!Path.empty())
|
|
|
|
addSystemInclude(DriverArgs, CC1Args, Path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case ToolChain::CST_Libstdcxx:
|
|
|
|
addLibStdCxxIncludePaths(DriverArgs, CC1Args);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Generic_GCC::findLibCxxIncludePath() const {
|
|
|
|
// FIXME: The Linux behavior would probaby be a better approach here.
|
|
|
|
return getDriver().SysRoot + "/usr/include/c++/v1";
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
|
|
|
|
llvm::opt::ArgStringList &CC1Args) const {
|
|
|
|
// By default, we don't assume we know where libstdc++ might be installed.
|
|
|
|
// FIXME: If we have a valid GCCInstallation, use it.
|
|
|
|
}
|
|
|
|
|
|
|
|
/// \brief Helper to add the variant paths of a libstdc++ installation.
|
|
|
|
bool Generic_GCC::addLibStdCXXIncludePaths(
|
|
|
|
Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple,
|
|
|
|
StringRef TargetMultiarchTriple, Twine IncludeSuffix,
|
|
|
|
const ArgList &DriverArgs, ArgStringList &CC1Args) const {
|
|
|
|
if (!getVFS().exists(Base + Suffix))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
addSystemInclude(DriverArgs, CC1Args, Base + Suffix);
|
|
|
|
|
|
|
|
// The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If
|
|
|
|
// that path exists or we have neither a GCC nor target multiarch triple, use
|
|
|
|
// this vanilla search path.
|
|
|
|
if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) ||
|
|
|
|
getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) {
|
|
|
|
addSystemInclude(DriverArgs, CC1Args,
|
|
|
|
Base + Suffix + "/" + GCCTriple + IncludeSuffix);
|
|
|
|
} else {
|
|
|
|
// Otherwise try to use multiarch naming schemes which have normalized the
|
|
|
|
// triples and put the triple before the suffix.
|
|
|
|
//
|
|
|
|
// GCC surprisingly uses *both* the GCC triple with a multilib suffix and
|
|
|
|
// the target triple, so we support that here.
|
|
|
|
addSystemInclude(DriverArgs, CC1Args,
|
|
|
|
Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix);
|
|
|
|
addSystemInclude(DriverArgs, CC1Args,
|
|
|
|
Base + "/" + TargetMultiarchTriple + Suffix);
|
|
|
|
}
|
|
|
|
|
|
|
|
addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
llvm::opt::DerivedArgList *
|
|
|
|
Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef,
|
|
|
|
Action::OffloadKind DeviceOffloadKind) const {
|
|
|
|
|
|
|
|
// If this tool chain is used for an OpenMP offloading device we have to make
|
|
|
|
// sure we always generate a shared library regardless of the commands the
|
|
|
|
// user passed to the host. This is required because the runtime library
|
|
|
|
// is required to load the device image dynamically at run time.
|
|
|
|
if (DeviceOffloadKind == Action::OFK_OpenMP) {
|
|
|
|
DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs());
|
|
|
|
const OptTable &Opts = getDriver().getOpts();
|
|
|
|
|
|
|
|
// Request the shared library. Given that these options are decided
|
|
|
|
// implicitly, they do not refer to any base argument.
|
|
|
|
DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared));
|
|
|
|
DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC));
|
|
|
|
|
|
|
|
// Filter all the arguments we don't care passing to the offloading
|
|
|
|
// toolchain as they can mess up with the creation of a shared library.
|
|
|
|
for (auto *A : Args) {
|
|
|
|
switch ((options::ID)A->getOption().getID()) {
|
|
|
|
default:
|
|
|
|
DAL->append(A);
|
|
|
|
break;
|
|
|
|
case options::OPT_shared:
|
|
|
|
case options::OPT_dynamic:
|
|
|
|
case options::OPT_static:
|
|
|
|
case options::OPT_fPIC:
|
|
|
|
case options::OPT_fno_PIC:
|
|
|
|
case options::OPT_fpic:
|
|
|
|
case options::OPT_fno_pic:
|
|
|
|
case options::OPT_fPIE:
|
|
|
|
case options::OPT_fno_PIE:
|
|
|
|
case options::OPT_fpie:
|
|
|
|
case options::OPT_fno_pie:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DAL;
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Generic_ELF::anchor() {}
|
|
|
|
|
|
|
|
void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs,
|
|
|
|
ArgStringList &CC1Args) const {
|
|
|
|
const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion();
|
|
|
|
bool UseInitArrayDefault =
|
|
|
|
getTriple().getArch() == llvm::Triple::aarch64 ||
|
|
|
|
getTriple().getArch() == llvm::Triple::aarch64_be ||
|
|
|
|
(getTriple().getOS() == llvm::Triple::Linux &&
|
|
|
|
(!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) ||
|
|
|
|
getTriple().getOS() == llvm::Triple::NaCl ||
|
|
|
|
(getTriple().getVendor() == llvm::Triple::MipsTechnologies &&
|
|
|
|
!getTriple().hasEnvironment());
|
|
|
|
|
|
|
|
if (DriverArgs.hasFlag(options::OPT_fuse_init_array,
|
|
|
|
options::OPT_fno_use_init_array, UseInitArrayDefault))
|
|
|
|
CC1Args.push_back("-fuse-init-array");
|
|
|
|
}
|