Files
clang-p2996/clang/lib/Driver/ToolChains/FreeBSD.cpp
Pirama Arumuga Nainar d60ff75b56 [Driver] Add -static-openmp driver option
Summary:
For Gnu, FreeBSD and NetBSD, this option forces linking with the static
OpenMP host runtime (similar to -static-libgcc and -static-libstdcxx).

Android's NDK will start the shared OpenMP runtime in addition to the static
libomp.  In this scenario, the linker will prefer to use the shared library by
default.  Add this option to enable linking with the static libomp.

Reviewers: Hahnfeld, danalbert, srhines, joerg, jdoerfert

Subscribers: guansong, cfe-commits

Tags: #clang

Fixes https://github.com/android-ndk/ndk/issues/1028

Differential Revision: https://reviews.llvm.org/D67200

llvm-svn: 371437
2019-09-09 18:31:41 +00:00

448 lines
14 KiB
C++

//===--- FreeBSD.cpp - FreeBSD ToolChain Implementations --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "FreeBSD.h"
#include "Arch/ARM.h"
#include "Arch/Mips.h"
#include "Arch/Sparc.h"
#include "CommonArgs.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Options.h"
#include "clang/Driver/SanitizerArgs.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/VirtualFileSystem.h"
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;
void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
claimNoWarnArgs(Args);
ArgStringList CmdArgs;
// When building 32-bit code on FreeBSD/amd64, we have to explicitly
// instruct as in the base system to assemble 32-bit code.
switch (getToolChain().getArch()) {
default:
break;
case llvm::Triple::x86:
CmdArgs.push_back("--32");
break;
case llvm::Triple::ppc:
CmdArgs.push_back("-a32");
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);
CmdArgs.push_back("-march");
CmdArgs.push_back(CPUName.data());
CmdArgs.push_back("-mabi");
CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data());
if (getToolChain().getTriple().isLittleEndian())
CmdArgs.push_back("-EL");
else
CmdArgs.push_back("-EB");
if (Arg *A = Args.getLastArg(options::OPT_G)) {
StringRef v = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-G" + v));
A->claim();
}
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb: {
arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args);
if (ABI == arm::FloatABI::Hard)
CmdArgs.push_back("-mfpu=vfp");
else
CmdArgs.push_back("-mfpu=softvfp");
switch (getToolChain().getTriple().getEnvironment()) {
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABI:
case llvm::Triple::EABI:
CmdArgs.push_back("-meabi=5");
break;
default:
CmdArgs.push_back("-matpcs");
}
break;
}
case llvm::Triple::sparc:
case llvm::Triple::sparcel:
case llvm::Triple::sparcv9: {
std::string CPU = getCPUName(Args, getToolChain().getTriple());
CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple()));
AddAssemblerKPIC(getToolChain(), Args, CmdArgs);
break;
}
}
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(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
const toolchains::FreeBSD &ToolChain =
static_cast<const toolchains::FreeBSD &>(getToolChain());
const Driver &D = ToolChain.getDriver();
const llvm::Triple::ArchType Arch = ToolChain.getArch();
const bool IsPIE =
!Args.hasArg(options::OPT_shared) &&
(Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault());
ArgStringList CmdArgs;
// Silence warning for "clang -g foo.o -o foo"
Args.ClaimAllArgs(options::OPT_g_Group);
// and "clang -emit-llvm foo.o -o foo"
Args.ClaimAllArgs(options::OPT_emit_llvm);
// and for "clang -w foo.o -o foo". Other warning options are already
// handled somewhere else.
Args.ClaimAllArgs(options::OPT_w);
if (!D.SysRoot.empty())
CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot));
if (IsPIE)
CmdArgs.push_back("-pie");
CmdArgs.push_back("--eh-frame-hdr");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-Bstatic");
} else {
if (Args.hasArg(options::OPT_rdynamic))
CmdArgs.push_back("-export-dynamic");
if (Args.hasArg(options::OPT_shared)) {
CmdArgs.push_back("-Bshareable");
} else {
CmdArgs.push_back("-dynamic-linker");
CmdArgs.push_back("/libexec/ld-elf.so.1");
}
if (ToolChain.getTriple().getOSMajorVersion() >= 9) {
if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc ||
Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) {
CmdArgs.push_back("--hash-style=both");
}
}
CmdArgs.push_back("--enable-new-dtags");
}
// Explicitly set the linker emulation for platforms that might not
// be the default emulation for the linker.
switch (Arch) {
case llvm::Triple::x86:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386_fbsd");
break;
case llvm::Triple::ppc:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32ppc_fbsd");
break;
case llvm::Triple::mips:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32btsmip_fbsd");
break;
case llvm::Triple::mipsel:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32ltsmip_fbsd");
break;
case llvm::Triple::mips64:
CmdArgs.push_back("-m");
if (tools::mips::hasMipsAbiArg(Args, "n32"))
CmdArgs.push_back("elf32btsmipn32_fbsd");
else
CmdArgs.push_back("elf64btsmip_fbsd");
break;
case llvm::Triple::mips64el:
CmdArgs.push_back("-m");
if (tools::mips::hasMipsAbiArg(Args, "n32"))
CmdArgs.push_back("elf32ltsmipn32_fbsd");
else
CmdArgs.push_back("elf64ltsmip_fbsd");
break;
case llvm::Triple::riscv32:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf32lriscv");
break;
case llvm::Triple::riscv64:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf64lriscv");
break;
default:
break;
}
if (Arg *A = Args.getLastArg(options::OPT_G)) {
if (ToolChain.getTriple().isMIPS()) {
StringRef v = A->getValue();
CmdArgs.push_back(Args.MakeArgString("-G" + v));
A->claim();
}
}
if (Output.isFilename()) {
CmdArgs.push_back("-o");
CmdArgs.push_back(Output.getFilename());
} else {
assert(Output.isNothing() && "Invalid output.");
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
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")));
const char *crtbegin = nullptr;
if (Args.hasArg(options::OPT_static))
crtbegin = "crtbeginT.o";
else if (Args.hasArg(options::OPT_shared) || IsPIE)
crtbegin = "crtbeginS.o";
else
crtbegin = "crtbegin.o";
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
}
Args.AddAllArgs(CmdArgs, options::OPT_L);
ToolChain.AddFilePathLibArgs(Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
Args.AddAllArgs(CmdArgs, options::OPT_e);
Args.AddAllArgs(CmdArgs, options::OPT_s);
Args.AddAllArgs(CmdArgs, options::OPT_t);
Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
Args.AddAllArgs(CmdArgs, options::OPT_r);
if (D.isUsingLTO()) {
assert(!Inputs.empty() && "Must have at least one input.");
AddGoldPlugin(ToolChain, Args, CmdArgs, Output, Inputs[0],
D.getLTOMode() == LTOK_Thin);
}
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs);
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA);
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
// Use the static OpenMP runtime with -static-openmp
bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) &&
!Args.hasArg(options::OPT_static);
addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP);
if (D.CCCIsCXX()) {
if (ToolChain.ShouldLinkCXXStdlib(Args))
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lm_p");
else
CmdArgs.push_back("-lm");
}
if (NeedsSanitizerDeps)
linkSanitizerRuntimeDeps(ToolChain, CmdArgs);
if (NeedsXRayDeps)
linkXRayRuntimeDeps(ToolChain, CmdArgs);
// FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding
// the default system libraries. Just mimic this for now.
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lgcc_p");
else
CmdArgs.push_back("-lgcc");
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-lgcc_eh");
} else if (Args.hasArg(options::OPT_pg)) {
CmdArgs.push_back("-lgcc_eh_p");
} else {
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lgcc_s");
CmdArgs.push_back("--no-as-needed");
}
if (Args.hasArg(options::OPT_pthread)) {
if (Args.hasArg(options::OPT_pg))
CmdArgs.push_back("-lpthread_p");
else
CmdArgs.push_back("-lpthread");
}
if (Args.hasArg(options::OPT_pg)) {
if (Args.hasArg(options::OPT_shared))
CmdArgs.push_back("-lc");
else
CmdArgs.push_back("-lc_p");
CmdArgs.push_back("-lgcc_p");
} else {
CmdArgs.push_back("-lc");
CmdArgs.push_back("-lgcc");
}
if (Args.hasArg(options::OPT_static)) {
CmdArgs.push_back("-lgcc_eh");
} else if (Args.hasArg(options::OPT_pg)) {
CmdArgs.push_back("-lgcc_eh_p");
} else {
CmdArgs.push_back("--as-needed");
CmdArgs.push_back("-lgcc_s");
CmdArgs.push_back("--no-as-needed");
}
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
if (Args.hasArg(options::OPT_shared) || IsPIE)
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o")));
else
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o")));
CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o")));
}
ToolChain.addProfileRTLibs(Args, CmdArgs);
const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath());
C.addCommand(std::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs));
}
/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly.
FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args)
: Generic_ELF(D, Triple, Args) {
// When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall
// back to '/usr/lib' if it doesn't exist.
if ((Triple.getArch() == llvm::Triple::x86 || Triple.isMIPS32() ||
Triple.getArch() == llvm::Triple::ppc) &&
D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o"))
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32");
else
getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
}
ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const {
if (getTriple().getOSMajorVersion() >= 10)
return ToolChain::CST_Libcxx;
return ToolChain::CST_Libstdcxx;
}
unsigned FreeBSD::GetDefaultDwarfVersion() const {
if (getTriple().getOSMajorVersion() < 12)
return 2;
return 4;
}
void FreeBSD::addLibStdCxxIncludePaths(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "",
"", "", DriverArgs, CC1Args);
}
void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CXXStdlibType Type = GetCXXStdlibType(Args);
bool Profiling = Args.hasArg(options::OPT_pg);
switch (Type) {
case ToolChain::CST_Libcxx:
CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++");
break;
case ToolChain::CST_Libstdcxx:
CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++");
break;
}
}
Tool *FreeBSD::buildAssembler() const {
return new tools::freebsd::Assembler(*this);
}
Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); }
llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const {
// FreeBSD uses SjLj exceptions on ARM oabi.
switch (getTriple().getEnvironment()) {
case llvm::Triple::GNUEABIHF:
case llvm::Triple::GNUEABI:
case llvm::Triple::EABI:
return llvm::ExceptionHandling::None;
default:
if (getTriple().getArch() == llvm::Triple::arm ||
getTriple().getArch() == llvm::Triple::thumb)
return llvm::ExceptionHandling::SjLj;
return llvm::ExceptionHandling::None;
}
}
bool FreeBSD::HasNativeLLVMSupport() const { return true; }
bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); }
SanitizerMask FreeBSD::getSupportedSanitizers() const {
const bool IsX86 = getTriple().getArch() == llvm::Triple::x86;
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
const bool IsMIPS64 = getTriple().isMIPS64();
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
Res |= SanitizerKind::PointerCompare;
Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Vptr;
if (IsX86_64 || IsMIPS64) {
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Thread;
}
if (IsX86 || IsX86_64) {
Res |= SanitizerKind::Function;
Res |= SanitizerKind::SafeStack;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;
}
if (IsX86_64)
Res |= SanitizerKind::Memory;
return Res;
}