summaryrefslogtreecommitdiff
path: root/lib/Driver/ToolChains/Darwin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Driver/ToolChains/Darwin.cpp')
-rw-r--r--lib/Driver/ToolChains/Darwin.cpp336
1 files changed, 286 insertions, 50 deletions
diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp
index c395c9a4430ed..5de7d7132df81 100644
--- a/lib/Driver/ToolChains/Darwin.cpp
+++ b/lib/Driver/ToolChains/Darwin.cpp
@@ -1,9 +1,8 @@
//===--- Darwin.cpp - Darwin 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.
+// 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
//
//===----------------------------------------------------------------------===//
@@ -12,6 +11,7 @@
#include "CommonArgs.h"
#include "clang/Basic/AlignedAllocation.h"
#include "clang/Basic/ObjCRuntime.h"
+#include "clang/Config/config.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/DriverDiagnostic.h"
@@ -462,6 +462,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// For LTO, pass the name of the optimization record file and other
// opt-remarks flags.
if (Args.hasFlag(options::OPT_fsave_optimization_record,
+ options::OPT_fsave_optimization_record_EQ,
options::OPT_fno_save_optimization_record, false)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-lto-pass-remarks-output");
@@ -469,7 +470,13 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
SmallString<128> F;
F = Output.getFilename();
- F += ".opt.yaml";
+ F += ".opt.";
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fsave_optimization_record_EQ))
+ F += A->getValue();
+ else
+ F += "yaml";
+
CmdArgs.push_back(Args.MakeArgString(F));
if (getLastProfileUseArg(Args)) {
@@ -484,20 +491,53 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(Opt));
}
}
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) {
+ CmdArgs.push_back("-mllvm");
+ std::string Passes =
+ std::string("-lto-pass-remarks-filter=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(Passes));
+ }
+
+ if (const Arg *A =
+ Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) {
+ CmdArgs.push_back("-mllvm");
+ std::string Format =
+ std::string("-lto-pass-remarks-format=") + A->getValue();
+ CmdArgs.push_back(Args.MakeArgString(Format));
+ }
}
// Propagate the -moutline flag to the linker in LTO.
- if (Args.hasFlag(options::OPT_moutline, options::OPT_mno_outline, false)) {
- if (getMachOToolChain().getMachOArchName(Args) == "arm64") {
- CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-machine-outliner");
+ if (Arg *A =
+ Args.getLastArg(options::OPT_moutline, options::OPT_mno_outline)) {
+ if (A->getOption().matches(options::OPT_moutline)) {
+ if (getMachOToolChain().getMachOArchName(Args) == "arm64") {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-machine-outliner");
- // Outline from linkonceodr functions by default in LTO.
+ // Outline from linkonceodr functions by default in LTO.
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back("-enable-linkonceodr-outlining");
+ }
+ } else {
+ // Disable all outlining behaviour if we have mno-outline. We need to do
+ // this explicitly, because targets which support default outlining will
+ // try to do work if we don't.
CmdArgs.push_back("-mllvm");
- CmdArgs.push_back("-enable-linkonceodr-outlining");
+ CmdArgs.push_back("-enable-machine-outliner=never");
}
}
+ // Setup statistics file output.
+ SmallString<128> StatsFile =
+ getStatsFileName(Args, Output, Inputs[0], getToolChain().getDriver());
+ if (!StatsFile.empty()) {
+ CmdArgs.push_back("-mllvm");
+ CmdArgs.push_back(Args.MakeArgString("-lto-stats-file=" + StatsFile.str()));
+ }
+
// It seems that the 'e' option is completely ignored for dynamic executables
// (the default), and with static executables, the last one wins, as expected.
Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t,
@@ -569,15 +609,26 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA,
if (getToolChain().ShouldLinkCXXStdlib(Args))
getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs);
- if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
+
+ bool NoStdOrDefaultLibs =
+ Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs);
+ bool ForceLinkBuiltins = Args.hasArg(options::OPT_fapple_link_rtlib);
+ if (!NoStdOrDefaultLibs || ForceLinkBuiltins) {
// link_ssp spec is empty.
- // Let the tool chain choose which runtime library to link.
- getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs);
+ // If we have both -nostdlib/nodefaultlibs and -fapple-link-rtlib then
+ // we just want to link the builtins, not the other libs like libSystem.
+ if (NoStdOrDefaultLibs && ForceLinkBuiltins) {
+ getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, "builtins");
+ } else {
+ // Let the tool chain choose which runtime library to link.
+ getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs,
+ ForceLinkBuiltins);
- // No need to do anything for pthreads. Claim argument to avoid warning.
- Args.ClaimAllArgs(options::OPT_pthread);
- Args.ClaimAllArgs(options::OPT_pthreads);
+ // No need to do anything for pthreads. Claim argument to avoid warning.
+ Args.ClaimAllArgs(options::OPT_pthread);
+ Args.ClaimAllArgs(options::OPT_pthreads);
+ }
}
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
@@ -869,6 +920,18 @@ void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const {
}
}
+/// Take a path that speculatively points into Xcode and return the
+/// `XCODE/Contents/Developer` path if it is an Xcode path, or an empty path
+/// otherwise.
+static StringRef getXcodeDeveloperPath(StringRef PathIntoXcode) {
+ static constexpr llvm::StringLiteral XcodeAppSuffix(
+ ".app/Contents/Developer");
+ size_t Index = PathIntoXcode.find(XcodeAppSuffix);
+ if (Index == StringRef::npos)
+ return "";
+ return PathIntoXcode.take_front(Index + XcodeAppSuffix.size());
+}
+
void DarwinClang::AddLinkARCArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
// Avoid linking compatibility stubs on i386 mac.
@@ -881,10 +944,27 @@ void DarwinClang::AddLinkARCArgs(const ArgList &Args,
runtime.hasSubscripting())
return;
- CmdArgs.push_back("-force_load");
SmallString<128> P(getDriver().ClangExecutable);
llvm::sys::path::remove_filename(P); // 'clang'
llvm::sys::path::remove_filename(P); // 'bin'
+
+ // 'libarclite' usually lives in the same toolchain as 'clang'. However, the
+ // Swift open source toolchains for macOS distribute Clang without libarclite.
+ // In that case, to allow the linker to find 'libarclite', we point to the
+ // 'libarclite' in the XcodeDefault toolchain instead.
+ if (getXcodeDeveloperPath(P).empty()) {
+ if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) {
+ // Try to infer the path to 'libarclite' in the toolchain from the
+ // specified SDK path.
+ StringRef XcodePathForSDK = getXcodeDeveloperPath(A->getValue());
+ if (!XcodePathForSDK.empty()) {
+ P = XcodePathForSDK;
+ llvm::sys::path::append(P, "Toolchains/XcodeDefault.xctoolchain/usr");
+ }
+ }
+ }
+
+ CmdArgs.push_back("-force_load");
llvm::sys::path::append(P, "lib", "arc", "libarclite_");
// Mash in the platform.
if (isTargetWatchOSSimulator())
@@ -1049,7 +1129,6 @@ void Darwin::addProfileRTLibs(const ArgList &Args,
addExportedSymbol(CmdArgs, "___llvm_profile_filename");
addExportedSymbol(CmdArgs, "___llvm_profile_raw_version");
addExportedSymbol(CmdArgs, "_lprofCurFilename");
- addExportedSymbol(CmdArgs, "_lprofMergeValueProfData");
}
addExportedSymbol(CmdArgs, "_lprofDirMode");
}
@@ -1076,7 +1155,8 @@ ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType(
}
void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ bool ForceLinkBuiltinRT) const {
// Call once to ensure diagnostic is printed if wrong value was specified
GetRuntimeLibType(Args);
@@ -1084,8 +1164,11 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
// libraries with -static.
if (Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_fapple_kext) ||
- Args.hasArg(options::OPT_mkernel))
+ Args.hasArg(options::OPT_mkernel)) {
+ if (ForceLinkBuiltinRT)
+ AddLinkRuntimeLib(Args, CmdArgs, "builtins");
return;
+ }
// Reject -static-libgcc for now, we can deal with this when and if someone
// cares. This is useful in situations where someone wants to statically link
@@ -1117,8 +1200,6 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args,
AddLinkRuntimeLib(Args, CmdArgs, "stats_client", RLO_AlwaysLink);
AddLinkSanitizerLibArgs(Args, CmdArgs, "stats");
}
- if (Sanitize.needsEsanRt())
- AddLinkSanitizerLibArgs(Args, CmdArgs, "esan");
const XRayArgs &XRay = getXRayArgs();
if (XRay.needsXRayRt()) {
@@ -1739,6 +1820,92 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const {
}
}
+// Returns the effective header sysroot path to use. This comes either from
+// -isysroot or --sysroot.
+llvm::StringRef DarwinClang::GetHeaderSysroot(const llvm::opt::ArgList &DriverArgs) const {
+ if(DriverArgs.hasArg(options::OPT_isysroot))
+ return DriverArgs.getLastArgValue(options::OPT_isysroot);
+ if (!getDriver().SysRoot.empty())
+ return getDriver().SysRoot;
+ return "/";
+}
+
+void DarwinClang::AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args) const {
+ const Driver &D = getDriver();
+
+ llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+
+ bool NoStdInc = DriverArgs.hasArg(options::OPT_nostdinc);
+ bool NoStdlibInc = DriverArgs.hasArg(options::OPT_nostdlibinc);
+ bool NoBuiltinInc = DriverArgs.hasArg(options::OPT_nobuiltininc);
+
+ // Add <sysroot>/usr/local/include
+ if (!NoStdInc && !NoStdlibInc) {
+ SmallString<128> P(Sysroot);
+ llvm::sys::path::append(P, "usr", "local", "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ // Add the Clang builtin headers (<resource>/include)
+ if (!NoStdInc && !NoBuiltinInc) {
+ SmallString<128> P(D.ResourceDir);
+ llvm::sys::path::append(P, "include");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ if (NoStdInc || NoStdlibInc)
+ return;
+
+ // Check for configure-time C include directories.
+ llvm::StringRef CIncludeDirs(C_INCLUDE_DIRS);
+ if (!CIncludeDirs.empty()) {
+ llvm::SmallVector<llvm::StringRef, 5> dirs;
+ CIncludeDirs.split(dirs, ":");
+ for (llvm::StringRef dir : dirs) {
+ llvm::StringRef Prefix =
+ llvm::sys::path::is_absolute(dir) ? llvm::StringRef(Sysroot) : "";
+ addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir);
+ }
+ } else {
+ // Otherwise, add <sysroot>/usr/include.
+ SmallString<128> P(Sysroot);
+ llvm::sys::path::append(P, "usr", "include");
+ addExternCSystemInclude(DriverArgs, CC1Args, P.str());
+ }
+}
+
+bool DarwinClang::AddGnuCPlusPlusIncludePaths(const llvm::opt::ArgList &DriverArgs,
+ llvm::opt::ArgStringList &CC1Args,
+ llvm::SmallString<128> Base,
+ llvm::StringRef Version,
+ llvm::StringRef ArchDir,
+ llvm::StringRef BitDir) const {
+ llvm::sys::path::append(Base, Version);
+
+ // Add the base dir
+ addSystemInclude(DriverArgs, CC1Args, Base);
+
+ // Add the multilib dirs
+ {
+ llvm::SmallString<128> P = Base;
+ if (!ArchDir.empty())
+ llvm::sys::path::append(P, ArchDir);
+ if (!BitDir.empty())
+ llvm::sys::path::append(P, BitDir);
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ // Add the backward dir
+ {
+ llvm::SmallString<128> P = Base;
+ llvm::sys::path::append(P, "backward");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+
+ return getVFS().exists(Base);
+}
+
void DarwinClang::AddClangCXXStdlibIncludeArgs(
const llvm::opt::ArgList &DriverArgs,
llvm::opt::ArgStringList &CC1Args) const {
@@ -1746,29 +1913,90 @@ void DarwinClang::AddClangCXXStdlibIncludeArgs(
// CC1Args.
// FIXME: this should not be necessary, remove usages in the frontend
// (e.g. HeaderSearchOptions::UseLibcxx) and don't pipe -stdlib.
+ // Also check whether this is used for setting library search paths.
ToolChain::AddClangCXXStdlibIncludeArgs(DriverArgs, CC1Args);
if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
DriverArgs.hasArg(options::OPT_nostdincxx))
return;
+ llvm::StringRef Sysroot = GetHeaderSysroot(DriverArgs);
+
switch (GetCXXStdlibType(DriverArgs)) {
case ToolChain::CST_Libcxx: {
- llvm::StringRef InstallDir = getDriver().getInstalledDir();
- if (InstallDir.empty())
- break;
- // On Darwin, libc++ may be installed alongside the compiler in
- // include/c++/v1.
- // Get from 'foo/bin' to 'foo/include/c++/v1'.
- SmallString<128> P = InstallDir;
- // Note that InstallDir can be relative, so we have to '..' and not
- // parent_path.
- llvm::sys::path::append(P, "..", "include", "c++", "v1");
- addSystemInclude(DriverArgs, CC1Args, P);
+ // On Darwin, libc++ is installed alongside the compiler in
+ // include/c++/v1, so get from '<install>/bin' to '<install>/include/c++/v1'.
+ {
+ llvm::SmallString<128> P = llvm::StringRef(getDriver().getInstalledDir());
+ // Note that P can be relative, so we have to '..' and not parent_path.
+ llvm::sys::path::append(P, "..", "include", "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
+ // Also add <sysroot>/usr/include/c++/v1 unless -nostdinc is used,
+ // to match the legacy behavior in CC1.
+ if (!DriverArgs.hasArg(options::OPT_nostdinc)) {
+ llvm::SmallString<128> P = Sysroot;
+ llvm::sys::path::append(P, "usr", "include", "c++", "v1");
+ addSystemInclude(DriverArgs, CC1Args, P);
+ }
break;
}
+
case ToolChain::CST_Libstdcxx:
- // FIXME: should we do something about it?
+ llvm::SmallString<128> UsrIncludeCxx = Sysroot;
+ llvm::sys::path::append(UsrIncludeCxx, "usr", "include", "c++");
+
+ llvm::Triple::ArchType arch = getTriple().getArch();
+ bool IsBaseFound = true;
+ switch (arch) {
+ default: break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.2.1",
+ "powerpc-apple-darwin10",
+ arch == llvm::Triple::ppc64 ? "ppc64" : "");
+ IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.0.0", "powerpc-apple-darwin10",
+ arch == llvm::Triple::ppc64 ? "ppc64" : "");
+ break;
+
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.2.1",
+ "i686-apple-darwin10",
+ arch == llvm::Triple::x86_64 ? "x86_64" : "");
+ IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.0.0", "i686-apple-darwin8",
+ "");
+ break;
+
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.2.1",
+ "arm-apple-darwin10",
+ "v7");
+ IsBaseFound |= AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.2.1",
+ "arm-apple-darwin10",
+ "v6");
+ break;
+
+ case llvm::Triple::aarch64:
+ IsBaseFound = AddGnuCPlusPlusIncludePaths(DriverArgs, CC1Args, UsrIncludeCxx,
+ "4.2.1",
+ "arm64-apple-darwin10",
+ "");
+ break;
+ }
+
+ if (!IsBaseFound) {
+ getDriver().Diag(diag::warn_drv_libstdcxx_not_found);
+ }
+
break;
}
}
@@ -2056,7 +2284,8 @@ DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args,
}
void MachO::AddLinkRuntimeLibArgs(const ArgList &Args,
- ArgStringList &CmdArgs) const {
+ ArgStringList &CmdArgs,
+ bool ForceLinkBuiltinRT) const {
// Embedded targets are simple at the moment, not supporting sanitizers and
// with different libraries for each member of the product { static, PIC } x
// { hard-float, soft-float }
@@ -2290,22 +2519,27 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args,
}
} else {
if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) {
- if (Args.hasArg(options::OPT_static) ||
- Args.hasArg(options::OPT_object) ||
- Args.hasArg(options::OPT_preload)) {
- CmdArgs.push_back("-lgcrt0.o");
- } else {
- CmdArgs.push_back("-lgcrt1.o");
+ if (isTargetMacOS() && isMacosxVersionLT(10, 9)) {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lgcrt0.o");
+ } else {
+ CmdArgs.push_back("-lgcrt1.o");
- // darwin_crt2 spec is empty.
+ // darwin_crt2 spec is empty.
+ }
+ // By default on OS X 10.8 and later, we don't link with a crt1.o
+ // file and the linker knows to use _main as the entry point. But,
+ // when compiling with -pg, we need to link with the gcrt1.o file,
+ // so pass the -no_new_main option to tell the linker to use the
+ // "start" symbol as the entry point.
+ if (isTargetMacOS() && !isMacosxVersionLT(10, 8))
+ CmdArgs.push_back("-no_new_main");
+ } else {
+ getDriver().Diag(diag::err_drv_clang_unsupported_opt_pg_darwin)
+ << isTargetMacOS();
}
- // By default on OS X 10.8 and later, we don't link with a crt1.o
- // file and the linker knows to use _main as the entry point. But,
- // when compiling with -pg, we need to link with the gcrt1.o file,
- // so pass the -no_new_main option to tell the linker to use the
- // "start" symbol as the entry point.
- if (isTargetMacOS() && !isMacosxVersionLT(10, 8))
- CmdArgs.push_back("-no_new_main");
} else {
if (Args.hasArg(options::OPT_static) ||
Args.hasArg(options::OPT_object) ||
@@ -2357,6 +2591,8 @@ SanitizerMask Darwin::getSupportedSanitizers() const {
const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64;
SanitizerMask Res = ToolChain::getSupportedSanitizers();
Res |= SanitizerKind::Address;
+ Res |= SanitizerKind::PointerCompare;
+ Res |= SanitizerKind::PointerSubtract;
Res |= SanitizerKind::Leak;
Res |= SanitizerKind::Fuzzer;
Res |= SanitizerKind::FuzzerNoLink;