aboutsummaryrefslogtreecommitdiff
path: root/lib/Driver/Tools.cpp
diff options
context:
space:
mode:
authorDaniel Dunbar <daniel@zuster.org>2009-03-26 16:23:12 +0000
committerDaniel Dunbar <daniel@zuster.org>2009-03-26 16:23:12 +0000
commit02633b541b04ad5ffc1c70f4c2feeeb13e607057 (patch)
tree005d8c3448d2cd9002babf3a4da10c9dffbe5c3a /lib/Driver/Tools.cpp
parent9d9963e73045ffc0fb9982633fa0bac3af14112e (diff)
Driver: Add darwin::Link tool.
- <rdar://problem/6717381> [driver] implement ld argument translation in new driver git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67760 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Driver/Tools.cpp')
-rw-r--r--lib/Driver/Tools.cpp444
1 files changed, 444 insertions, 0 deletions
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index 4bc034fc84..248df2786f 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -22,8 +22,11 @@
#include "clang/Driver/Util.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
#include "InputInfo.h"
+#include "ToolChains.h"
using namespace clang::driver;
using namespace clang::driver::tools;
@@ -490,6 +493,447 @@ void darwin::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
Dest.addCommand(new Command(Exec, CmdArgs));
}
+static const char *MakeFormattedString(const ArgList &Args,
+ const llvm::format_object_base &Fmt) {
+ std::string Str;
+ llvm::raw_string_ostream(Str) << Fmt;
+ return Args.MakeArgString(Str.c_str());
+}
+
+/// Helper routine for seeing if we should use dsymutil; this is a
+/// gcc compatible hack, we should remove it and use the input
+/// type information.
+static bool isSourceSuffix(const char *Str) {
+ // match: 'C', 'CPP', 'c', 'cc', 'cp', 'c++', 'cpp', 'cxx', 'm',
+ // 'mm'.
+ switch (strlen(Str)) {
+ default:
+ return false;
+ case 1:
+ return (memcmp(Str, "C", 1) == 0 ||
+ memcmp(Str, "c", 1) == 0 ||
+ memcmp(Str, "m", 1) == 0);
+ case 2:
+ return (memcmp(Str, "cc", 2) == 0 ||
+ memcmp(Str, "cp", 2) == 0 ||
+ memcmp(Str, "mm", 2) == 0);
+ case 3:
+ return (memcmp(Str, "CPP", 3) == 0 ||
+ memcmp(Str, "c++", 3) == 0 ||
+ memcmp(Str, "cpp", 3) == 0 ||
+ memcmp(Str, "cxx", 3) == 0);
+ }
+}
+
+static bool isMacosxVersionLT(unsigned (&A)[3], unsigned (&B)[3]) {
+ for (unsigned i=0; i < 3; ++i) {
+ if (A[i] > B[i]) return false;
+ if (A[i] < B[i]) return true;
+ }
+ return false;
+}
+
+static bool isMacosxVersionLT(unsigned (&A)[3],
+ unsigned V0, unsigned V1=0, unsigned V2=0) {
+ unsigned B[3] = { V0, V1, V2 };
+ return isMacosxVersionLT(A, B);
+}
+
+static bool isMacosxVersionGTE(unsigned(&A)[3],
+ unsigned V0, unsigned V1=0, unsigned V2=0) {
+ return !isMacosxVersionLT(A, V0, V1, V2);
+}
+
+const toolchains::Darwin_X86 &darwin::Link::getDarwinToolChain() const {
+ return reinterpret_cast<const toolchains::Darwin_X86&>(getToolChain());
+}
+
+void darwin::Link::AddDarwinArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from darwin_arch spec.
+ CmdArgs.push_back("-arch");
+ CmdArgs.push_back(getToolChain().getArchName().c_str());
+}
+
+void darwin::Link::AddDarwinSubArch(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ // Derived from darwin_subarch spec, not sure what the distinction
+ // exists for but at least for this chain it is the same.
+ AddDarwinArch(Args, CmdArgs);
+}
+
+void darwin::Link::AddLinkArgs(const ArgList &Args,
+ ArgStringList &CmdArgs) const {
+ const Driver &D = getToolChain().getHost().getDriver();
+
+ // Derived from the "link" spec.
+ Args.AddAllArgs(CmdArgs, options::OPT_static);
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-dynamic");
+ if (Args.hasArg(options::OPT_fgnu_runtime)) {
+ // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu
+ // here. How do we wish to handle such things?
+ }
+
+ if (!Args.hasArg(options::OPT_dynamiclib)) {
+ if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
+ AddDarwinArch(Args, CmdArgs);
+ CmdArgs.push_back("-force_cpusubtype_ALL");
+ } else
+ AddDarwinSubArch(Args, CmdArgs);
+
+ Args.AddLastArg(CmdArgs, options::OPT_bundle);
+ Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader);
+ Args.AddAllArgs(CmdArgs, options::OPT_client__name);
+
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_compatibility__version)) ||
+ (A = Args.getLastArg(options::OPT_current__version)) ||
+ (A = Args.getLastArg(options::OPT_install__name)))
+ D.Diag(clang::diag::err_drv_argument_only_allowed_with)
+ << A->getAsString(Args) << "-dynamiclib";
+
+ Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs);
+ Args.AddLastArg(CmdArgs, options::OPT_private__bundle);
+ } else {
+ CmdArgs.push_back("-dylib");
+
+ Arg *A;
+ if ((A = Args.getLastArg(options::OPT_bundle)) ||
+ (A = Args.getLastArg(options::OPT_bundle__loader)) ||
+ (A = Args.getLastArg(options::OPT_client__name)) ||
+ (A = Args.getLastArg(options::OPT_force__flat__namespace)) ||
+ (A = Args.getLastArg(options::OPT_keep__private__externs)) ||
+ (A = Args.getLastArg(options::OPT_private__bundle)))
+ D.Diag(clang::diag::err_drv_argument_not_allowed_with)
+ << A->getAsString(Args) << "-dynamiclib";
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version,
+ "-dylib_compatibility_version");
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version,
+ "-dylib_current_version");
+
+ if (Args.hasArg(options::OPT_force__cpusubtype__ALL)) {
+ AddDarwinArch(Args, CmdArgs);
+ // NOTE: We don't add -force_cpusubtype_ALL on this path. Ok.
+ } else
+ AddDarwinSubArch(Args, CmdArgs);
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name,
+ "-dylib_install_name");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_all__load);
+ Args.AddAllArgs(CmdArgs, options::OPT_allowable__client);
+ Args.AddLastArg(CmdArgs, options::OPT_bind__at__load);
+ Args.AddLastArg(CmdArgs, options::OPT_dead__strip);
+ Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylib__file);
+ Args.AddLastArg(CmdArgs, options::OPT_dynamic);
+ Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list);
+ Args.AddLastArg(CmdArgs, options::OPT_flat__namespace);
+ Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names);
+ Args.AddAllArgs(CmdArgs, options::OPT_image__base);
+ Args.AddAllArgs(CmdArgs, options::OPT_init);
+
+ if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ)) {
+ if (!Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
+ // FIXME: I don't understand what is going on here. This is
+ // supposed to come from darwin_ld_minversion, but gcc doesn't
+ // seem to be following that; it must be getting overridden
+ // somewhere.
+ CmdArgs.push_back("-macosx_version_min");
+ CmdArgs.push_back(getDarwinToolChain().getMacosxVersionStr());
+ }
+ } else {
+ // Adding all arguments doesn't make sense here but this is what
+ // gcc does.
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_mmacosx_version_min_EQ,
+ "-macosx_version_min");
+ }
+
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_miphoneos_version_min_EQ,
+ "-iphoneos_version_min");
+ Args.AddLastArg(CmdArgs, options::OPT_nomultidefs);
+ Args.AddLastArg(CmdArgs, options::OPT_multi__module);
+ Args.AddLastArg(CmdArgs, options::OPT_single__module);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined);
+ Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused);
+
+ if (Args.hasArg(options::OPT_fpie))
+ CmdArgs.push_back("-pie");
+
+ Args.AddLastArg(CmdArgs, options::OPT_prebind);
+ Args.AddLastArg(CmdArgs, options::OPT_noprebind);
+ Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding);
+ Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules);
+ Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectcreate);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectorder);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg1addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segprot);
+ Args.AddAllArgs(CmdArgs, options::OPT_segaddr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table);
+ Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__library);
+ Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella);
+ Args.AddAllArgsTranslated(CmdArgs, options::OPT_isysroot, "-syslibroot");
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace);
+ Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints);
+ Args.AddAllArgs(CmdArgs, options::OPT_umbrella);
+ Args.AddAllArgs(CmdArgs, options::OPT_undefined);
+ Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list);
+ Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches);
+
+ if (!Args.hasArg(options::OPT_weak__reference__mismatches)) {
+ CmdArgs.push_back("-weak_reference_mismatches");
+ CmdArgs.push_back("non-weak");
+ }
+
+ Args.AddLastArg(CmdArgs, options::OPT_X_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_y);
+ Args.AddLastArg(CmdArgs, options::OPT_w);
+ Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size);
+ Args.AddAllArgs(CmdArgs, options::OPT_segs__read__);
+ Args.AddLastArg(CmdArgs, options::OPT_seglinkedit);
+ Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectalign);
+ Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols);
+ Args.AddAllArgs(CmdArgs, options::OPT_segcreate);
+ Args.AddLastArg(CmdArgs, options::OPT_whyload);
+ Args.AddLastArg(CmdArgs, options::OPT_whatsloaded);
+ Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name);
+ Args.AddLastArg(CmdArgs, options::OPT_dylinker);
+ Args.AddLastArg(CmdArgs, options::OPT_Mach);
+}
+
+void darwin::Link::ConstructJob(Compilation &C, const JobAction &JA,
+ Job &Dest, const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &Args,
+ const char *LinkingOutput) const {
+ assert(Output.getType() == types::TY_Image && "Invalid linker output type.");
+ // The logic here is derived from gcc's behavior; most of which
+ // comes from specs (starting with link_command). Consult gcc for
+ // more information.
+
+ // FIXME: The spec references -fdump= which seems to have
+ // disappeared?
+
+ ArgStringList CmdArgs;
+
+ // I'm not sure why this particular decomposition exists in gcc, but
+ // we follow suite for ease of comparison.
+ AddLinkArgs(Args, CmdArgs);
+
+ // FIXME: gcc has %{x} in here. How could this ever happen? Cruft?
+ Args.AddAllArgs(CmdArgs, options::OPT_d_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_s);
+ Args.AddAllArgs(CmdArgs, options::OPT_t);
+ Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag);
+ Args.AddAllArgs(CmdArgs, options::OPT_u_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_A);
+ Args.AddLastArg(CmdArgs, options::OPT_e);
+ Args.AddAllArgs(CmdArgs, options::OPT_m_Separate);
+ Args.AddAllArgs(CmdArgs, options::OPT_r);
+
+ // FIXME: This is just being pedantically bug compatible, gcc
+ // doesn't *mean* to forward this, it just does (yay for pattern
+ // matching). It doesn't work, of course.
+ Args.AddAllArgs(CmdArgs, options::OPT_object);
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ unsigned MacosxVersion[3];
+ if (Arg *A = Args.getLastArg(options::OPT_mmacosx_version_min_EQ)) {
+ bool HadExtra;
+ if (!Driver::GetReleaseVersion(A->getValue(Args), MacosxVersion[0],
+ MacosxVersion[1], MacosxVersion[2],
+ HadExtra) ||
+ HadExtra) {
+ const Driver &D = getToolChain().getHost().getDriver();
+ D.Diag(clang::diag::err_drv_invalid_version_number)
+ << A->getAsString(Args);
+ }
+ } else {
+ getDarwinToolChain().getMacosxVersion(MacosxVersion);
+ }
+
+ if (!Args.hasArg(options::OPT_A) &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ // Derived from startfile spec.
+ if (Args.hasArg(options::OPT_dynamiclib)) {
+ // Derived from darwin_dylib1 spec.
+ if (Args.hasArg(options::OPT_miphoneos_version_min_EQ) ||
+ isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-ldylib1.o");
+ else
+ CmdArgs.push_back("-ldylib1.10.5.o");
+ } else {
+ if (Args.hasArg(options::OPT_bundle)) {
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-lbundle1.o");
+ } else {
+ if (Args.hasArg(options::OPT_pg)) {
+ 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.
+ }
+ } else {
+ if (Args.hasArg(options::OPT_static) ||
+ Args.hasArg(options::OPT_object) ||
+ Args.hasArg(options::OPT_preload)) {
+ CmdArgs.push_back("-lcrt0.o");
+ } else {
+ // Derived from darwin_crt1 spec.
+ if (Args.hasArg(options::OPT_miphoneos_version_min_EQ) ||
+ isMacosxVersionLT(MacosxVersion, 10, 5)) {
+ CmdArgs.push_back("-lcrt1.o");
+ } else {
+ CmdArgs.push_back("-lcrt1.10.5.o");
+
+ // darwin_crt2 spec is empty.
+ }
+ }
+ }
+ }
+ }
+
+ if (Args.hasArg(options::OPT_shared_libgcc) &&
+ !Args.hasArg(options::OPT_miphoneos_version_min_EQ) &&
+ isMacosxVersionLT(MacosxVersion, 10, 5)) {
+ const char *Str = getToolChain().GetFilePath(C, "crt3.o").c_str();
+ CmdArgs.push_back(Args.MakeArgString(Str));
+ }
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+ if (Args.hasArg(options::OPT_fopenmp))
+ // This is more complicated in gcc...
+ CmdArgs.push_back("-lgomp");
+
+ // FIXME: Derive these correctly.
+ const char *TCDir = getDarwinToolChain().getToolChainDir().c_str();
+ if (getToolChain().getArchName() == "x86_64") {
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir)));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/x86_64", TCDir)));
+ }
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/%s", TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s", TCDir)));
+ // Intentionally duplicated for (temporary) gcc bug compatibility.
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s", TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/../../../%s", TCDir, TCDir)));
+ CmdArgs.push_back(MakeFormattedString(Args,
+ llvm::format("-L/usr/lib/gcc/%s/../../..", TCDir)));
+
+ for (InputInfoList::const_iterator
+ it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
+ const InputInfo &II = *it;
+ if (II.isFilename())
+ CmdArgs.push_back(II.getFilename());
+ else
+ II.getInputArg().renderAsInput(Args, CmdArgs);
+ }
+
+ if (LinkingOutput) {
+ CmdArgs.push_back("-arch_multiple");
+ CmdArgs.push_back("-final_output");
+ CmdArgs.push_back(LinkingOutput);
+ }
+
+ if (Args.hasArg(options::OPT_fprofile_arcs) ||
+ Args.hasArg(options::OPT_fprofile_generate) ||
+ Args.hasArg(options::OPT_fcreate_profile) ||
+ Args.hasArg(options::OPT_coverage))
+ CmdArgs.push_back("-lgcov");
+
+ if (Args.hasArg(options::OPT_fnested_functions))
+ CmdArgs.push_back("-allow_stack_execute");
+
+ if (!Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nodefaultlibs)) {
+ // link_ssp spec is empty.
+
+ // Derived from libgcc spec.
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_static");
+ } else if (Args.hasArg(options::OPT_static_libgcc)) {
+ CmdArgs.push_back("-lgcc_eh");
+ CmdArgs.push_back("-lgcc");
+ } else if (Args.hasArg(options::OPT_miphoneos_version_min_EQ)) {
+ // Derived from darwin_iphoneos_libgcc spec.
+ CmdArgs.push_back("-lgcc_s.10.5");
+ CmdArgs.push_back("-lgcc");
+ } else if (Args.hasArg(options::OPT_shared_libgcc) ||
+ Args.hasArg(options::OPT_fexceptions) ||
+ Args.hasArg(options::OPT_fgnu_runtime)) {
+ if (isMacosxVersionLT(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ else
+ CmdArgs.push_back("-lgcc_s.10.5");
+ CmdArgs.push_back("-lgcc");
+ } else {
+ if (isMacosxVersionLT(MacosxVersion, 10, 5) &&
+ isMacosxVersionGTE(MacosxVersion, 10, 3, 9))
+ CmdArgs.push_back("-lgcc_s.10.4");
+ if (isMacosxVersionGTE(MacosxVersion, 10, 5))
+ CmdArgs.push_back("-lgcc_s.10.5");
+ CmdArgs.push_back("-lgcc");
+ }
+
+ // Derived from lib spec.
+ if (!Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-lSystem");
+ }
+
+ if (!Args.hasArg(options::OPT_A) &&
+ !Args.hasArg(options::OPT_nostdlib) &&
+ !Args.hasArg(options::OPT_nostartfiles)) {
+ // endfile_spec is empty.
+ }
+
+ Args.AddAllArgs(CmdArgs, options::OPT_T_Group);
+ Args.AddAllArgs(CmdArgs, options::OPT_F);
+
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "collect2").c_str());
+ Dest.addCommand(new Command(Exec, CmdArgs));
+
+ if (Args.getLastArg(options::OPT_g_Group) &&
+ !Args.getLastArg(options::OPT_gstabs) &&
+ !Args.getLastArg(options::OPT_g0)) {
+ // FIXME: This is gross, but matches gcc. The test only considers
+ // the suffix (not the -x type), and then only of the first
+ // input. Awesome.
+ const char *Suffix = strchr(Inputs[0].getBaseInput(), '.');
+ if (Suffix && isSourceSuffix(Suffix + 1)) {
+ const char *Exec =
+ Args.MakeArgString(getToolChain().GetProgramPath(C, "dsymutil").c_str());
+ ArgStringList CmdArgs;
+ CmdArgs.push_back(Output.getFilename());
+ C.getJobs().addCommand(new Command(Exec, CmdArgs));
+ }
+ }
+}
+
void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA,
Job &Dest, const InputInfo &Output,
const InputInfoList &Inputs,