aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/Driver/ToolChains/Gnu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Driver/ToolChains/Gnu.cpp')
-rw-r--r--clang/lib/Driver/ToolChains/Gnu.cpp250
1 files changed, 219 insertions, 31 deletions
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index da197e476621..c8a7fce07ef1 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -35,8 +35,7 @@ using namespace clang;
using namespace llvm::opt;
using tools::addMultilibFlag;
-
-void tools::GnuTool::anchor() {}
+using tools::addPathIfExists;
static bool forwardToGCC(const Option &O) {
// Don't forward inputs from the original command line. They are added from
@@ -189,7 +188,8 @@ void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA,
GCCName = "gcc";
const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName));
- C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
}
void tools::gcc::Preprocessor::RenderExtraToolArgs(
@@ -304,12 +304,14 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) {
if (T.getEnvironment() == llvm::Triple::GNUX32)
return "elf32_x86_64";
return "elf_x86_64";
+ case llvm::Triple::ve:
+ return "elf64ve";
default:
return nullptr;
}
}
-static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) {
+static bool getPIE(const ArgList &Args, const ToolChain &TC) {
if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_r) || Args.hasArg(options::OPT_static_pie))
return false;
@@ -317,17 +319,16 @@ static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) {
Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
options::OPT_nopie);
if (!A)
- return ToolChain.isPIEDefault();
+ return TC.isPIEDefault();
return A->getOption().matches(options::OPT_pie);
}
-static bool getStaticPIE(const ArgList &Args,
- const toolchains::Linux &ToolChain) {
+static bool getStaticPIE(const ArgList &Args, const ToolChain &TC) {
bool HasStaticPIE = Args.hasArg(options::OPT_static_pie);
// -no-pie is an alias for -nopie. So, handling -nopie takes care of
// -no-pie as well.
if (HasStaticPIE && Args.hasArg(options::OPT_nopie)) {
- const Driver &D = ToolChain.getDriver();
+ const Driver &D = TC.getDriver();
const llvm::opt::OptTable &Opts = D.getOpts();
const char *StaticPIEName = Opts.getOptionName(options::OPT_static_pie);
const char *NoPIEName = Opts.getOptionName(options::OPT_nopie);
@@ -341,13 +342,55 @@ static bool getStatic(const ArgList &Args) {
!Args.hasArg(options::OPT_static_pie);
}
+void tools::gnutools::StaticLibTool::ConstructJob(
+ Compilation &C, const JobAction &JA, const InputInfo &Output,
+ const InputInfoList &Inputs, const ArgList &Args,
+ const char *LinkingOutput) const {
+ const Driver &D = getToolChain().getDriver();
+
+ // Silence warning for "clang -g foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_g_Group);
+ // and "clang -emit-llvm foo.o -o foo"
+ Args.ClaimAllArgs(options::OPT_emit_llvm);
+ // and for "clang -w foo.o -o foo". Other warning options are already
+ // handled somewhere else.
+ Args.ClaimAllArgs(options::OPT_w);
+ // Silence warnings when linking C code with a C++ '-stdlib' argument.
+ Args.ClaimAllArgs(options::OPT_stdlib_EQ);
+
+ // GNU ar tool command "ar <options> <output_file> <input_files>".
+ ArgStringList CmdArgs;
+ // Create and insert file members with a deterministic index.
+ CmdArgs.push_back("rcsD");
+ CmdArgs.push_back(Output.getFilename());
+ AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
+
+ // Delete old output archive file if it already exists before generating a new
+ // archive file.
+ auto OutputFileName = Output.getFilename();
+ if (Output.isFilename() && llvm::sys::fs::exists(OutputFileName)) {
+ if (std::error_code EC = llvm::sys::fs::remove(OutputFileName)) {
+ D.Diag(diag::err_drv_unable_to_remove_file) << EC.message();
+ return;
+ }
+ }
+
+ const char *Exec = Args.MakeArgString(getToolChain().GetStaticLibToolPath());
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
+}
+
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());
+ // FIXME: The Linker class constructor takes a ToolChain and not a
+ // Generic_ELF, so the static_cast might return a reference to a invalid
+ // instance (see PR45061). Ideally, the Linker constructor needs to take a
+ // Generic_ELF instead.
+ const toolchains::Generic_ELF &ToolChain =
+ static_cast<const toolchains::Generic_ELF &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple &Triple = getToolChain().getEffectiveTriple();
@@ -355,6 +398,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool isAndroid = ToolChain.getTriple().isAndroid();
const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU();
+ const bool IsVE = ToolChain.getTriple().isVE();
const bool IsPIE = getPIE(Args, ToolChain);
const bool IsStaticPIE = getStaticPIE(Args, ToolChain);
const bool IsStatic = getStatic(Args);
@@ -418,8 +462,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (isAndroid)
CmdArgs.push_back("--warn-shared-textrel");
- for (const auto &Opt : ToolChain.ExtraOpts)
- CmdArgs.push_back(Opt.c_str());
+ ToolChain.addExtraOpts(CmdArgs);
CmdArgs.push_back("--eh-frame-hdr");
@@ -446,10 +489,9 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back("-export-dynamic");
if (!Args.hasArg(options::OPT_shared) && !IsStaticPIE) {
- const std::string Loader =
- D.DyldPrefix + ToolChain.getDynamicLinker(Args);
CmdArgs.push_back("-dynamic-linker");
- CmdArgs.push_back(Args.MakeArgString(Loader));
+ CmdArgs.push_back(Args.MakeArgString(Twine(D.DyldPrefix) +
+ ToolChain.getDynamicLinker(Args)));
}
}
@@ -475,6 +517,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
}
+ if (IsVE) {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("max-page-size=0x4000000");
+ }
+
if (IsIAMCU)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o")));
else if (HasCRTBeginEndFiles) {
@@ -502,7 +549,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
// Add crtfastmath.o if available and fast math is enabled.
- ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs);
+ ToolChain.addFastMathRuntimeIfAvailable(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
@@ -512,7 +559,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
- AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0],
+ addLTOOptions(ToolChain, Args, CmdArgs, Output, Inputs[0],
D.getLTOMode() == LTOK_Thin);
}
@@ -623,12 +670,11 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA,
}
}
- // Add HIP offloading linker script args if required.
- AddHIPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA,
- *this);
+ Args.AddAllArgs(CmdArgs, options::OPT_T);
const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath());
- C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
}
void tools::gnutools::Assembler::ConstructJob(Compilation &C,
@@ -646,6 +692,7 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
llvm::Reloc::Model RelocationModel;
unsigned PICLevel;
bool IsPIE;
+ const char *DefaultAssembler = "as";
std::tie(RelocationModel, PICLevel, IsPIE) =
ParsePICArgs(getToolChain(), Args);
@@ -866,6 +913,8 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName));
break;
}
+ case llvm::Triple::ve:
+ DefaultAssembler = "nas";
}
for (const Arg *A : Args.filtered(options::OPT_ffile_prefix_map_EQ,
@@ -890,8 +939,10 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C,
for (const auto &II : Inputs)
CmdArgs.push_back(II.getFilename());
- const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as"));
- C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(DefaultAssembler));
+ C.addCommand(std::make_unique<Command>(
+ JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs));
// Handle the debug info splitting at object creation time if we're
// creating an object.
@@ -1527,7 +1578,7 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
};
// currently only support the set of multilibs like riscv-gnu-toolchain does.
// TODO: support MULTILIB_REUSE
- SmallVector<RiscvMultilib, 8> RISCVMultilibSet = {
+ constexpr RiscvMultilib RISCVMultilibSet[] = {
{"rv32i", "ilp32"}, {"rv32im", "ilp32"}, {"rv32iac", "ilp32"},
{"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
{"rv64imafdc", "lp64d"}};
@@ -1767,7 +1818,7 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
StringRef MinorStr = Second.first;
if (Second.second.empty()) {
if (size_t EndNumber = MinorStr.find_first_not_of("0123456789")) {
- GoodVersion.PatchSuffix = MinorStr.substr(EndNumber);
+ GoodVersion.PatchSuffix = std::string(MinorStr.substr(EndNumber));
MinorStr = MinorStr.slice(0, EndNumber);
}
}
@@ -1793,7 +1844,7 @@ Generic_GCC::GCCVersion Generic_GCC::GCCVersion::Parse(StringRef VersionText) {
if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) ||
GoodVersion.Patch < 0)
return BadVersion;
- GoodVersion.PatchSuffix = PatchText.substr(EndNumber);
+ GoodVersion.PatchSuffix = std::string(PatchText.substr(EndNumber));
}
}
@@ -1848,7 +1899,7 @@ void Generic_GCC::GCCInstallationDetector::init(
if (GCCToolchainDir.back() == '/')
GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the /
- Prefixes.push_back(GCCToolchainDir);
+ Prefixes.push_back(std::string(GCCToolchainDir));
} else {
// If we have a SysRoot, try that first.
if (!D.SysRoot.empty()) {
@@ -1975,6 +2026,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
// Non-Solaris is much simpler - most systems just go with "/usr".
if (SysRoot.empty() && TargetTriple.getOS() == llvm::Triple::Linux) {
// Yet, still look for RHEL devtoolsets.
+ Prefixes.push_back("/opt/rh/devtoolset-9/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-8/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-7/root/usr");
Prefixes.push_back("/opt/rh/devtoolset-6/root/usr");
@@ -2090,6 +2142,7 @@ void Generic_GCC::GCCInstallationDetector::AddDefaultGCCPrefixes(
static const char *const RISCV64Triples[] = {"riscv64-unknown-linux-gnu",
"riscv64-linux-gnu",
"riscv64-unknown-elf",
+ "riscv64-redhat-linux",
"riscv64-suse-linux"};
static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"};
@@ -2460,7 +2513,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
StringRef VersionText = llvm::sys::path::filename(LI->path());
GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
if (CandidateVersion.Major != -1) // Filter obviously bad entries.
- if (!CandidateGCCInstallPaths.insert(LI->path()).second)
+ if (!CandidateGCCInstallPaths.insert(std::string(LI->path())).second)
continue; // Saw this path before; no need to look at it again.
if (CandidateVersion.isOlderThan(4, 1, 1))
continue;
@@ -2572,7 +2625,7 @@ bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig(
Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: ToolChain(D, Triple, Args), GCCInstallation(D),
- CudaInstallation(D, Triple, Args) {
+ CudaInstallation(D, Triple, Args), RocmInstallation(D, Triple, Args) {
getProgramPaths().push_back(getDriver().getInstalledDir());
if (getDriver().getInstalledDir() != getDriver().Dir)
getProgramPaths().push_back(getDriver().Dir);
@@ -2605,6 +2658,7 @@ void Generic_GCC::printVerboseInfo(raw_ostream &OS) const {
// Print the information about how we detected the GCC installation.
GCCInstallation.print(OS);
CudaInstallation.print(OS);
+ RocmInstallation.print(OS);
}
bool Generic_GCC::IsUnwindTablesDefault(const ArgList &Args) const {
@@ -2666,6 +2720,140 @@ bool Generic_GCC::IsIntegratedAssemblerDefault() const {
}
}
+static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs,
+ const Multilib &Multilib,
+ StringRef InstallPath,
+ ToolChain::path_list &Paths) {
+ if (const auto &PathsCallback = Multilibs.filePathsCallback())
+ for (const auto &Path : PathsCallback(Multilib))
+ addPathIfExists(D, InstallPath + Path, Paths);
+}
+
+void Generic_GCC::PushPPaths(ToolChain::path_list &PPaths) {
+ // Cross-compiling binutils and GCC installations (vanilla and openSUSE at
+ // least) put various tools in a triple-prefixed directory off of the parent
+ // of the GCC installation. We use the GCC triple here to ensure that we end
+ // up with tools that support the same amount of cross compiling as the
+ // detected GCC installation. For example, if we find a GCC installation
+ // targeting x86_64, but it is a bi-arch GCC installation, it can also be
+ // used to target i386.
+ if (GCCInstallation.isValid()) {
+ PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" +
+ GCCInstallation.getTriple().str() + "/bin")
+ .str());
+ }
+}
+
+void Generic_GCC::AddMultilibPaths(const Driver &D,
+ const std::string &SysRoot,
+ const std::string &OSLibDir,
+ const std::string &MultiarchTriple,
+ path_list &Paths) {
+ // Add the multilib suffixed paths where they are available.
+ if (GCCInstallation.isValid()) {
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ const std::string &LibPath =
+ std::string(GCCInstallation.getParentLibPath());
+
+ // Add toolchain / multilib specific file paths.
+ addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
+ GCCInstallation.getInstallPath(), Paths);
+
+ // Sourcery CodeBench MIPS toolchain holds some libraries under
+ // a biarch-like suffix of the GCC installation.
+ addPathIfExists(
+ D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(),
+ Paths);
+
+ // GCC cross compiling toolchains will install target libraries which ship
+ // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as
+ // any part of the GCC installation in
+ // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat
+ // debatable, but is the reality today. We need to search this tree even
+ // when we have a sysroot somewhere else. It is the responsibility of
+ // whomever is doing the cross build targeting a sysroot using a GCC
+ // installation that is *not* within the system root to ensure two things:
+ //
+ // 1) Any DSOs that are linked in from this tree or from the install path
+ // above must be present on the system root and found via an
+ // appropriate rpath.
+ // 2) There must not be libraries installed into
+ // <prefix>/<triple>/<libdir> unless they should be preferred over
+ // those within the system root.
+ //
+ // Note that this matches the GCC behavior. See the below comment for where
+ // Clang diverges from GCC's behavior.
+ addPathIfExists(D,
+ LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir +
+ SelectedMultilib.osSuffix(),
+ Paths);
+
+ // If the GCC installation we found is inside of the sysroot, we want to
+ // prefer libraries installed in the parent prefix of the GCC installation.
+ // It is important to *not* use these paths when the GCC installation is
+ // outside of the system root as that can pick up unintended libraries.
+ // This usually happens when there is an external cross compiler on the
+ // host system, and a more minimal sysroot available that is the target of
+ // the cross. Note that GCC does include some of these directories in some
+ // configurations but this seems somewhere between questionable and simply
+ // a bug.
+ if (StringRef(LibPath).startswith(SysRoot)) {
+ addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths);
+ addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths);
+ }
+ }
+}
+
+void Generic_GCC::AddMultiarchPaths(const Driver &D,
+ const std::string &SysRoot,
+ const std::string &OSLibDir,
+ path_list &Paths) {
+ // Try walking via the GCC triple path in case of biarch or multiarch GCC
+ // installations with strange symlinks.
+ if (GCCInstallation.isValid()) {
+ addPathIfExists(D,
+ SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() +
+ "/../../" + OSLibDir,
+ Paths);
+
+ // Add the 'other' biarch variant path
+ Multilib BiarchSibling;
+ if (GCCInstallation.getBiarchSibling(BiarchSibling)) {
+ addPathIfExists(
+ D, GCCInstallation.getInstallPath() + BiarchSibling.gccSuffix(),
+ Paths);
+ }
+
+ // See comments above on the multilib variant for details of why this is
+ // included even from outside the sysroot.
+ const std::string &LibPath =
+ std::string(GCCInstallation.getParentLibPath());
+ const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
+ const Multilib &Multilib = GCCInstallation.getMultilib();
+ addPathIfExists(
+ D, LibPath + "/../" + GCCTriple.str() + "/lib" + Multilib.osSuffix(),
+ Paths);
+
+ // See comments above on the multilib variant for details of why this is
+ // only included from within the sysroot.
+ if (StringRef(LibPath).startswith(SysRoot))
+ addPathIfExists(D, LibPath, Paths);
+ }
+}
+
+void Generic_GCC::AddMultilibIncludeArgs(const ArgList &DriverArgs,
+ ArgStringList &CC1Args) const {
+ // Add include directories specific to the selected multilib set and multilib.
+ if (GCCInstallation.isValid()) {
+ const auto &Callback = Multilibs.includeDirsCallback();
+ if (Callback) {
+ for (const auto &Path : Callback(GCCInstallation.getMultilib()))
+ addExternCSystemIncludeIfExists(
+ DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path);
+ }
+ }
+}
+
void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
ArgStringList &CC1Args) const {
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
@@ -2696,7 +2884,7 @@ static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs,
!VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) {
if (Version > MaxVersion) {
MaxVersion = Version;
- MaxVersionString = VersionText;
+ MaxVersionString = std::string(VersionText);
}
}
}
@@ -2706,7 +2894,6 @@ static std::string DetectLibcxxIncludePath(llvm::vfs::FileSystem &vfs,
void
Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
- const std::string& SysRoot = getDriver().SysRoot;
auto AddIncludePath = [&](std::string Path) {
std::string IncludePath = DetectLibcxxIncludePath(getVFS(), Path);
if (IncludePath.empty() || !getVFS().exists(IncludePath))
@@ -2722,6 +2909,7 @@ Generic_GCC::addLibCxxIncludePaths(const llvm::opt::ArgList &DriverArgs,
// If this is a development, non-installed, clang, libcxx will
// not be found at ../include/c++ but it likely to be found at
// one of the following two locations:
+ std::string SysRoot = computeSysRoot();
if (AddIncludePath(SysRoot + "/usr/local/include/c++"))
return;
if (AddIncludePath(SysRoot + "/usr/include/c++"))