From: Daniel Dunbar Date: Thu, 26 Mar 2009 16:23:12 +0000 (+0000) Subject: Driver: Add darwin::Link tool. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=02633b541b04ad5ffc1c70f4c2feeeb13e607057;p=clang Driver: Add darwin::Link tool. - [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 --- diff --git a/include/clang/Basic/DiagnosticDriverKinds.td b/include/clang/Basic/DiagnosticDriverKinds.td index b1b83b5c4b..760caaae78 100644 --- a/include/clang/Basic/DiagnosticDriverKinds.td +++ b/include/clang/Basic/DiagnosticDriverKinds.td @@ -35,6 +35,12 @@ def err_drv_missing_argument : Error< "argument to '%0' is missing (expected %1 %plural{1:value|:values}1)">; def err_drv_invalid_Xarch_argument : Error< "invalid Xarch argument: '%0'">; +def err_drv_argument_only_allowed_with : Error< + "invalid argument '%0' only allowed with '%1'">; +def err_drv_argument_not_allowed_with : Error< + "invalid argument '%0' not allowed with '%1'">; +def err_drv_invalid_version_number : Error< + "invalid version number in '%0'">; def warn_drv_input_file_unused : Warning< "%0: '%1' input file unused when '%2' is present">; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 31ff34fd2f..1b0bdfaad3 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -38,6 +38,9 @@ Darwin_X86::Darwin_X86(const HostInfo &Host, const char *Arch, GCCVersion[1] = _GCCVersion[1]; GCCVersion[2] = _GCCVersion[2]; + llvm::raw_string_ostream(MacosxVersionMin) + << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; + ToolChainDir = "i686-apple-darwin"; ToolChainDir += llvm::utostr(DarwinVersion[0]); ToolChainDir += "/"; @@ -93,13 +96,6 @@ Darwin_X86::~Darwin_X86() { delete it->second; } -std::string Darwin_X86::getMacosxVersionMin() const { - std::string Res; - llvm::raw_string_ostream OS(Res); - OS << "10." << DarwinVersion[0] - 4 << '.' << DarwinVersion[1]; - return OS.str(); -} - Tool &Darwin_X86::SelectTool(const Compilation &C, const JobAction &JA) const { Action::ActionClass Key; @@ -125,7 +121,7 @@ Tool &Darwin_X86::SelectTool(const Compilation &C, case Action::AssembleJobClass: T = new tools::darwin::Assemble(*this); break; case Action::LinkJobClass: - T = new tools::gcc::Link(*this); break; + T = new tools::darwin::Link(*this, MacosxVersionMin.c_str()); break; case Action::LipoJobClass: T = new tools::darwin::Lipo(*this); break; } @@ -147,7 +143,7 @@ DerivedArgList *Darwin_X86::TranslateArgs(InputArgList &Args) const { if (!Args.hasArg(options::OPT_mmacosx_version_min_EQ, false)) { const Option *O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - DAL->append(DAL->MakeJoinedArg(O, getMacosxVersionMin().c_str())); + DAL->append(DAL->MakeJoinedArg(O, MacosxVersionMin.c_str())); } for (ArgList::iterator it = Args.begin(), ie = Args.end(); it != ie; ++it) { diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 7548b9ec53..5e7bdb5f7b 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -56,7 +56,11 @@ class VISIBILITY_HIDDEN Darwin_X86 : public ToolChain { /// The directory suffix for this tool chain. std::string ToolChainDir; - std::string getMacosxVersionMin() const; + /// The default macosx-version-min of this tool chain; empty until + /// initialized. + mutable std::string MacosxVersionMin; + + const char *getMacosxVersionMin() const; public: Darwin_X86(const HostInfo &Host, const char *Arch, const char *Platform, @@ -64,6 +68,26 @@ public: const unsigned (&GCCVersion)[3]); ~Darwin_X86(); + void getDarwinVersion(unsigned (&Res)[3]) const { + Res[0] = DarwinVersion[0]; + Res[1] = DarwinVersion[1]; + Res[2] = DarwinVersion[2]; + } + + void getMacosxVersion(unsigned (&Res)[3]) const { + Res[0] = 10; + Res[1] = DarwinVersion[0] - 4; + Res[2] = DarwinVersion[1]; + } + + const char *getMacosxVersionStr() const { + return MacosxVersionMin.c_str(); + } + + const std::string &getToolChainDir() const { + return ToolChainDir; + } + virtual DerivedArgList *TranslateArgs(InputArgList &Args) const; virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const; @@ -72,9 +96,6 @@ public: virtual bool IsUnwindTablesDefault() const; virtual const char *GetDefaultRelocationModel() const; virtual const char *GetForcedPicModel() const; - -private: - const std::string &getToolChainDir() const { return ToolChainDir; } }; /// Darwin_GCC - Generic Darwin tool chain using gcc. 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(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, diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h index 672096e391..2b06a3d04d 100644 --- a/lib/Driver/Tools.h +++ b/lib/Driver/Tools.h @@ -17,6 +17,10 @@ namespace clang { namespace driver { +namespace toolchains { + class Darwin_X86; +} + namespace tools { class VISIBILITY_HIDDEN Clang : public Tool { @@ -127,6 +131,34 @@ namespace darwin { const char *LinkingOutput) const; }; + class VISIBILITY_HIDDEN Link : public Tool { + void AddDarwinArch(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddDarwinSubArch(const ArgList &Args, ArgStringList &CmdArgs) const; + void AddLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const; + + /// The default macosx-version-min. + const char *MacosxVersionMin; + + const toolchains::Darwin_X86 &getDarwinToolChain() const; + + public: + Link(const ToolChain &TC, + const char *_MacosxVersionMin) + : Tool("darwin::Link", TC), MacosxVersionMin(_MacosxVersionMin) { + } + + virtual bool acceptsPipedInput() const { return false; } + virtual bool canPipeOutput() const { return false; } + virtual bool hasIntegratedCPP() const { return false; } + + virtual void ConstructJob(Compilation &C, const JobAction &JA, + Job &Dest, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &TCArgs, + const char *LinkingOutput) const; + }; + class VISIBILITY_HIDDEN Lipo : public Tool { public: Lipo(const ToolChain &TC) : Tool("darwin::Lipo", TC) {} diff --git a/test/Driver/bindings.c b/test/Driver/bindings.c index 9495eb2fba..f6cd235f7d 100644 --- a/test/Driver/bindings.c +++ b/test/Driver/bindings.c @@ -51,6 +51,6 @@ // RUN: clang -ccc-host-triple i386-apple-darwin9 -ccc-print-bindings %s 2> %t && // RUN: grep 'bind - "clang", inputs: \[".*bindings.c"\], output: ".*\.s"' %t && // RUN: grep 'bind - "darwin::Assemble", inputs: \[".*\.s"\], output: ".*\.o"' %t && -// RUN: grep 'bind - "gcc::Link", inputs: \[".*\.o"\], output: "a.out"' %t && +// RUN: grep 'bind - "darwin::Link", inputs: \[".*\.o"\], output: "a.out"' %t && // RUN: true