The attached patch changes clang to use ld instead of gcc on linux. I
tested this on
* Debian Lenny Amd64
* Debian Lenny i386
* DebianSqueeze Amd64,
* DebianSqueeze i386,
* Debian Squeeze Arm,
* Fedora 13 X86_64,
* Fedora 13 i686,
* OpenSuse 11_3 X86_64,
* OpenSuse 11_3 i686,
* Ubuntu Lucid Amd64,
* Ubuntu Lucid i386,
* Ubuntu Maverick Amd64,
* Ubuntu Maverick i386,
The patch still needs some cleanup and refactoring, but there are some
points I would like to get some feedback already
*) How do you detect which distribution the host is? The current patch is ad hoc
*) I assumed it was better to do this check at runtime. This way I can
for example copy a binary to a chroot and it will work.
*) I could not find a way to detect if the distro is 32 or 64 bits at runtime
*) Part of the reason the patch is so big is because I forced the
clang invocation of ld to be *identical* to that done by gcc. If we
relax this a bit to allow the options to be in a different order the
patch gets a bit simpler. Any preferences?
*) I am dropping support for running gcc for linking. I can keep it
in, but would prefer to just add any other distro that someone might
want.
Cheers,
Rafael
diff --git a/include/clang/Driver/Options.td b/include/clang/Driver/Options.td
index da762be..728a9e1 100644
--- a/include/clang/Driver/Options.td
+++ b/include/clang/Driver/Options.td
@@ -610,6 +610,7 @@ def undefined : JoinedOrSeparate<"-undefined">, Group<u_Group>;
def undef : Flag<"-undef">, Group<u_Group>;
def unexported__symbols__list : Separate<"-unexported_symbols_list">;
def u : JoinedOrSeparate<"-u">, Group<u_Group>;
+def use_gold_plugin : Flag<"-use-gold-plugin">;
def v : Flag<"-v">,
HelpText<"Show commands to run and use verbose output">;
def weak_l : Joined<"-weak-l">, Flags<[LinkerInput]>;
diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp
index 126e3fd..5542106 100644
--- a/lib/Driver/ToolChains.cpp
+++ b/lib/Driver/ToolChains.cpp
@@ -23,6 +23,7 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/System/Path.h"
@@ -1177,28 +1178,274 @@ Tool &AuroraUX::SelectTool(const Compilation &C, const JobAction &JA) const {
/// Linux toolchain (very bare-bones at the moment).
+enum LinuxDistro {
+ DebianLennyAmd64,
+ DebianLennyi386,
+ DebianSqueezeAmd64,
+ DebianSqueezei386,
+ DebianSqueezeArm,
+ Fedora13X86_64,
+ Fedora13i686,
+ OpenSuse11_3X86_64,
+ OpenSuse11_3i686,
+ UbuntuLucidAmd64,
+ UbuntuLucidi386,
+ UbuntuMaverickAmd64,
+ UbuntuMavericki386,
+ UnknownDistro
+};
+
+static LinuxDistro DetectLinuxDistro() {
+ llvm::Triple::ArchType Arch;
+#if defined(__arm__)
+ Arch = llvm::Triple::arm;
+#elif defined(__i386__)
+ Arch = llvm::Triple::x86;
+#elif defined(__x86_64__)
+ Arch = llvm::Triple::x86_64;
+#else
+ Arch = llvm::Triple::UnknownArch;
+#endif
+
+ llvm::OwningPtr<const llvm::MemoryBuffer>
+ LsbRelease(llvm::MemoryBuffer::getFile("/etc/lsb-release"));
+ if (LsbRelease) {
+ llvm::StringRef Data = LsbRelease.get()->getBuffer();
+ llvm::SmallVector<llvm::StringRef, 8> Lines;
+ Data.split(Lines, "\n");
+ for (unsigned int i = 0, s = Lines.size(); i < s; ++ i) {
+ if (Lines[i] == "DISTRIB_CODENAME=maverick") {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::x86:
+ return UbuntuMavericki386;
+ case llvm::Triple::x86_64:
+ return UbuntuMaverickAmd64;
+ }
+ }
+ if (Lines[i] == "DISTRIB_CODENAME=lucid") {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::x86:
+ return UbuntuLucidi386;
+ case llvm::Triple::x86_64:
+ return UbuntuLucidAmd64;
+ }
+ }
+ }
+ return UnknownDistro;
+ }
+
+ llvm::OwningPtr<const llvm::MemoryBuffer>
+ RHRelease(llvm::MemoryBuffer::getFile("/etc/redhat-release"));
+ if (RHRelease) {
+ llvm::StringRef Data = RHRelease.get()->getBuffer();
+ if (Data.startswith("Fedora release 13 (Goddard)")) {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::x86:
+ return Fedora13i686;
+ case llvm::Triple::x86_64:
+ return Fedora13X86_64;
+ }
+ }
+ return UnknownDistro;
+ }
+
+ llvm::OwningPtr<const llvm::MemoryBuffer>
+ DebianVersion(llvm::MemoryBuffer::getFile("/etc/debian_version"));
+ if (DebianVersion) {
+ llvm::StringRef Data = DebianVersion.get()->getBuffer();
+ if (Data[0] == '5') {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::x86:
+ return DebianLennyi386;
+ case llvm::Triple::x86_64:
+ return DebianLennyAmd64;
+ }
+ } else if (Data.startswith("squeeze/sid")) {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::arm:
+ return DebianSqueezeArm;
+ case llvm::Triple::x86:
+ return DebianSqueezei386;
+ case llvm::Triple::x86_64:
+ return DebianSqueezeAmd64;
+ }
+ }
+ return UnknownDistro;
+ }
+
+ llvm::OwningPtr<const llvm::MemoryBuffer>
+ SuseRelease(llvm::MemoryBuffer::getFile("/etc/SuSE-release"));
+ if (SuseRelease) {
+ llvm::StringRef Data = SuseRelease.get()->getBuffer();
+ if (Data.startswith("openSUSE 11.3")) {
+ switch (Arch) {
+ default:
+ return UnknownDistro;
+ case llvm::Triple::x86:
+ return OpenSuse11_3i686;
+ case llvm::Triple::x86_64:
+ return OpenSuse11_3X86_64;
+ }
+ }
+ return UnknownDistro;
+ }
+
+ return UnknownDistro;
+}
+
Linux::Linux(const HostInfo &Host, const llvm::Triple& Triple)
: Generic_ELF(Host, Triple) {
- getFilePaths().push_back(getDriver().Dir +
- "/../lib/clang/" CLANG_VERSION_STRING "/");
- getFilePaths().push_back("/lib/");
- getFilePaths().push_back("/usr/lib/");
-
- // Depending on the Linux distribution, any combination of lib{,32,64} is
- // possible. E.g. Debian uses lib and lib32 for mixed i386/x86-64 systems,
- // openSUSE uses lib and lib64 for the same purpose.
- getFilePaths().push_back("/lib32/");
- getFilePaths().push_back("/usr/lib32/");
- getFilePaths().push_back("/lib64/");
- getFilePaths().push_back("/usr/lib64/");
-
- // FIXME: Figure out some way to get gcc's libdir
- // (e.g. /usr/lib/gcc/i486-linux-gnu/4.3/ for Ubuntu 32-bit); we need
- // crtbegin.o/crtend.o/etc., and want static versions of various
- // libraries. If we had our own crtbegin.o/crtend.o/etc, we could probably
- // get away with using shared versions in /usr/lib, though.
- // We could fall back to the approach we used for includes (a massive
- // list), but that's messy at best.
+
+ std::string Lib32 = "lib";
+ std::string Lib64 = "lib";
+ std::string Suffix32 = "";
+ std::string Suffix64 = "";
+ std::string Base = "";
+ std::string GccTriple = "";
+ Opt1 = "";
+ Opt2 = "";
+ Opt3 = "";
+ HashStyle = "";
+
+ LinuxDistro Distro = DetectLinuxDistro();
+
+ if (Distro == UnknownDistro)
+ llvm::report_fatal_error("Unknown linux distribution.");
+
+ if (Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuLucidi386)
+ Opt3 = "-z relro";
+
+ if (Distro == Fedora13X86_64 || Distro == Fedora13i686 ||
+ Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386)
+ HashStyle = "gnu";
+
+ if (Distro == DebianSqueezei386 || Distro == DebianSqueezeAmd64 ||
+ Distro == DebianSqueezeArm ||
+ Distro == DebianLennyi386 || Distro == DebianLennyAmd64 ||
+ Distro == UbuntuLucidi386 || Distro == UbuntuLucidAmd64)
+ HashStyle = "both";
+
+ if (Distro == DebianLennyAmd64 || Distro == DebianSqueezeAmd64 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuMaverickAmd64 ||
+ Distro == Fedora13X86_64 ||
+ Distro == OpenSuse11_3X86_64)
+ Suffix32 = "/32";
+
+ if (Distro == DebianLennyi386 || Distro == DebianSqueezei386 ||
+ Distro == UbuntuLucidi386 || Distro == UbuntuMavericki386)
+ Suffix64 = "/64";
+
+ if (Distro == DebianLennyAmd64 || Distro == DebianSqueezeAmd64 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuMaverickAmd64)
+ Lib32 = "lib32";
+
+ if (Distro == DebianLennyi386 || Distro == DebianSqueezei386 ||
+ Distro == UbuntuLucidi386 || Distro == UbuntuMavericki386 ||
+ Distro == Fedora13X86_64 ||
+ Distro == OpenSuse11_3X86_64)
+ Lib64 = "lib64";
+
+ if (Distro == Fedora13X86_64 || Distro == Fedora13i686) {
+ Opt1 = "--no-add-needed";
+ Opt2 = "--build-id";
+ }
+
+ if (Distro == DebianSqueezeAmd64 || Distro == DebianSqueezei386 ||
+ Distro == DebianSqueezeArm ||
+ Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuLucidi386 ||
+ Distro == OpenSuse11_3X86_64 || Distro == OpenSuse11_3i686)
+ Opt1 = "--build-id";
+
+ if (Distro == DebianSqueezeAmd64 || Distro == UbuntuMaverickAmd64 ||
+ Distro == DebianLennyAmd64 || Distro == UbuntuLucidAmd64)
+ GccTriple = "x86_64-linux-gnu";
+ if (Distro == DebianSqueezei386 || Distro == UbuntuLucidi386 ||
+ Distro == DebianLennyi386)
+ GccTriple = "i486-linux-gnu";
+ if (Distro == DebianSqueezeArm)
+ GccTriple = "arm-linux-gnueabi";
+ if (Distro == UbuntuMavericki386)
+ GccTriple = "i686-linux-gnu";
+ if (Distro == Fedora13i686)
+ GccTriple = "i686-redhat-linux";
+ if (Distro == Fedora13X86_64)
+ GccTriple = "x86_64-redhat-linux";
+ if (Distro == OpenSuse11_3X86_64)
+ GccTriple = "x86_64-suse-linux";
+ if (Distro == OpenSuse11_3i686)
+ GccTriple = "i586-suse-linux";
+
+ if (Distro == DebianLennyAmd64 || Distro == DebianLennyi386)
+ Base = "/usr/lib/gcc/" + GccTriple +"/4.3.2";
+ if (Distro == DebianSqueezeAmd64 || Distro == UbuntuMaverickAmd64 ||
+ Distro == DebianSqueezei386 || Distro == UbuntuMavericki386 ||
+ Distro == DebianSqueezeArm)
+ Base = "/usr/lib/gcc/" + GccTriple +"/4.4.5";
+ if (Distro == UbuntuLucidi386 || Distro == UbuntuLucidAmd64)
+ Base = "/usr/lib/gcc/" + GccTriple +"/4.4.3";
+ if (Distro == Fedora13X86_64 || Distro == Fedora13i686)
+ Base = "/usr/lib/gcc/" + GccTriple +"/4.4.4";
+ if (Distro == OpenSuse11_3X86_64 || Distro == OpenSuse11_3i686)
+ Base = "/usr/" + Lib64 + "/gcc/" + GccTriple + "/4.5";
+
+ path_list &Paths = getFilePaths();
+ bool Is32Bits = getArch() == llvm::Triple::x86;
+
+ std::string Suffix;
+ std::string Lib;
+
+ if (Is32Bits) {
+ Suffix = Suffix32;
+ Lib = Lib32;
+ } else {
+ Suffix = Suffix64;
+ Lib = Lib64;
+ }
+
+ llvm::sys::Path LinkerPath(Base + "/../../../../" + GccTriple + "/bin/ld");
+ if (LinkerPath.exists())
+ Linker = LinkerPath.str();
+ else
+ Linker = GetProgramPath("ld");
+
+ Paths.push_back(Base + Suffix);
+ if (Distro != OpenSuse11_3X86_64 && Distro != OpenSuse11_3i686)
+ Paths.push_back(Base + Suffix);
+ if (Distro != Fedora13i686 && Distro != OpenSuse11_3i686 &&
+ Distro != DebianSqueezeArm) {
+ if (Distro == OpenSuse11_3X86_64 && Is32Bits)
+ Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
+ Paths.push_back(Base + "/../../../../" + Lib);
+ Paths.push_back("/lib/../" + Lib);
+ Paths.push_back("/usr/lib/../" + Lib);
+ }
+ if (!Suffix.empty()) {
+ Paths.push_back(Base);
+ if (Distro != OpenSuse11_3X86_64)
+ Paths.push_back(Base);
+ }
+ if (Distro == OpenSuse11_3X86_64 || Distro == OpenSuse11_3i686)
+ Paths.push_back(Base + "/../../../../" + GccTriple + "/lib");
+ Paths.push_back(Base + "/../../..");
+ if ((!Is32Bits && (Distro == UbuntuMaverickAmd64 || Distro == UbuntuLucidAmd64)) ||
+ (Is32Bits && (Distro == UbuntuMavericki386 || Distro == UbuntuLucidi386)))
+ Paths.push_back("/usr/lib/" + GccTriple);
+}
+
+bool Linux::HasNativeLLVMSupport() const {
+ return true;
}
Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {
@@ -1213,6 +1460,8 @@ Tool &Linux::SelectTool(const Compilation &C, const JobAction &JA) const {
switch (Key) {
case Action::AssembleJobClass:
T = new tools::linuxtools::Assemble(*this); break;
+ case Action::LinkJobClass:
+ T = new tools::linuxtools::Link(*this); break;
default:
T = &Generic_GCC::SelectTool(C, JA);
}
diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h
index b98f176..1d1a9ce 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -317,7 +317,15 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF {
public:
Linux(const HostInfo &Host, const llvm::Triple& Triple);
+ virtual bool HasNativeLLVMSupport() const;
+
virtual Tool &SelectTool(const Compilation &C, const JobAction &JA) const;
+
+ std::string Linker;
+ std::string Opt1;
+ std::string Opt2;
+ std::string Opt3;
+ std::string HashStyle;
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index cdaea98..77a7783 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -3141,6 +3141,152 @@ void linuxtools::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
C.addCommand(new Command(JA, *this, Exec, CmdArgs));
}
+void linuxtools::Link::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());
+ const Driver &D = ToolChain.getDriver();
+ ArgStringList CmdArgs;
+
+ if (!ToolChain.Opt1.empty())
+ CmdArgs.push_back(ToolChain.Opt1.c_str());
+
+ if (!Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--eh-frame-hdr");
+ }
+
+ if (!ToolChain.Opt2.empty())
+ CmdArgs.push_back(ToolChain.Opt2.c_str());
+
+ if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::x86_64) {
+ CmdArgs.push_back("-m");
+ if (ToolChain.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("elf_i386");
+ else
+ CmdArgs.push_back("elf_x86_64");
+ }
+
+ if (ToolChain.getArch() == llvm::Triple::arm) {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-Bstatic");
+ else if (Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-shared");
+ CmdArgs.push_back("-dynamic-linker");
+ CmdArgs.push_back("/lib/ld-linux.so.3");
+ CmdArgs.push_back("-X");
+ }
+
+ if (!ToolChain.HashStyle.empty())
+ CmdArgs.push_back(Args.MakeArgString("--hash-style=" +
+ ToolChain.HashStyle));
+
+ if (ToolChain.getArch() == llvm::Triple::arm) {
+ CmdArgs.push_back("-m");
+ CmdArgs.push_back("armelf_linux_eabi");
+ }
+
+ if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::x86_64) {
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-static");
+ } else if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ } else if (ToolChain.getArch() == llvm::Triple::x86 ||
+ ToolChain.getArch() == llvm::Triple::x86_64) {
+ CmdArgs.push_back("-dynamic-linker");
+ if (ToolChain.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("/lib/ld-linux.so.2");
+ else
+ CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
+ }
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ if (!ToolChain.Opt3.empty())
+ CmdArgs.push_back(ToolChain.Opt3.c_str());
+
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o")));
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o")));
+
+ const char *crtbegin;
+ if (Args.hasArg(options::OPT_static))
+ crtbegin = "crtbeginT.o";
+ else if (Args.hasArg(options::OPT_shared))
+ crtbegin = "crtbeginS.o";
+ else
+ crtbegin = "crtbegin.o";
+
+ CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin)));
+
+ Args.AddAllArgs(CmdArgs, options::OPT_L);
+
+ const ToolChain::path_list Paths = ToolChain.getFilePaths();
+
+ for (ToolChain::path_list::const_iterator i = Paths.begin(),
+ e = Paths.end();
+ i != e; ++i) {
+ const std::string &s = *i;
+ CmdArgs.push_back(Args.MakeArgString(std::string("-L") + s));
+ }
+
+ AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
+
+
+ if (D.CCCIsCXX) {
+ ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
+ CmdArgs.push_back("-lm");
+ CmdArgs.push_back("-lgcc_s");
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("-lc");
+ CmdArgs.push_back("-lgcc_s");
+ if (!Args.hasArg(options::OPT_shared))
+ CmdArgs.push_back("-lgcc");
+ } else {
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+ CmdArgs.push_back("-lgcc");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("-lgcc_eh");
+ } else {
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ CmdArgs.push_back("-lc");
+ if (Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--end-group");
+ } else {
+ CmdArgs.push_back("-lgcc");
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ CmdArgs.push_back("--no-as-needed");
+ }
+ }
+
+ if (Args.hasArg(options::OPT_shared))
+ 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")));
+
+ if (Args.hasArg(options::OPT_use_gold_plugin)) {
+ CmdArgs.push_back("-plugin");
+ std::string Plugin = ToolChain.getDriver().Dir + "/../lib/LLVMgold.so";
+ CmdArgs.push_back(Args.MakeArgString(Plugin));
+ }
+
+ C.addCommand(new Command(JA, *this, ToolChain.Linker.c_str(), CmdArgs));
+}
void minix::Assemble::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h
index 63faf91..edfb2df 100644
--- a/lib/Driver/Tools.h
+++ b/lib/Driver/Tools.h
@@ -348,6 +348,18 @@ namespace linuxtools {
const ArgList &TCArgs,
const char *LinkingOutput) const;
};
+ class LLVM_LIBRARY_VISIBILITY Link : public Tool {
+ public:
+ Link(const ToolChain &TC) : Tool("linux::Link", "linker", TC) {}
+
+ virtual bool hasIntegratedCPP() const { return false; }
+
+ virtual void ConstructJob(Compilation &C, const JobAction &JA,
+ const InputInfo &Output,
+ const InputInfoList &Inputs,
+ const ArgList &TCArgs,
+ const char *LinkingOutput) const;
+ };
}
/// minix -- Directly call GNU Binutils assembler and linker
namespace minix {
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits