Updated patch attached. Improvements from the previous one include not
using #ifdefs, some fixes for c++ and simplifications. Unlike the
previous patch the ld line is not exactly the one produced by gcc, but
has the same options.
Tested on the same distros as before. For both C and C++ I checked the
ld command line of
$CC main.o -o main
$CC main.o -o main -static
$CC f.o -o f.so -shared
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..f5ffa3e 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,263 @@ 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) {
+ 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 = "";
+
+ llvm::Triple::ArchType Arch =
+ llvm::Triple(getDriver().DefaultHostTriple).getArch();
+ LinuxDistro Distro = DetectLinuxDistro(Arch);
+
+ if (Distro == UnknownDistro)
+ llvm::report_fatal_error("Unknown linux distribution.");
+
+ if (Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuLucidi386)
+ ExtraOpts.push_back("-z relro");
+
+ if (Distro == DebianSqueezeArm)
+ ExtraOpts.push_back("-X");
+
+ if (Distro == Fedora13X86_64 || Distro == Fedora13i686 ||
+ Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386)
+ ExtraOpts.push_back("--hash-style=gnu");
+
+ if (Distro == DebianSqueezei386 || Distro == DebianSqueezeAmd64 ||
+ Distro == DebianSqueezeArm ||
+ Distro == DebianLennyi386 || Distro == DebianLennyAmd64 ||
+ Distro == UbuntuLucidi386 || Distro == UbuntuLucidAmd64)
+ ExtraOpts.push_back("--hash-style=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)
+ ExtraOpts.push_back("--no-add-needed");
+
+ if (Distro == DebianSqueezeAmd64 || Distro == DebianSqueezei386 ||
+ Distro == DebianSqueezeArm ||
+ Distro == UbuntuMaverickAmd64 || Distro == UbuntuMavericki386 ||
+ Distro == UbuntuLucidAmd64 || Distro == UbuntuLucidi386 ||
+ Distro == OpenSuse11_3X86_64 || Distro == OpenSuse11_3i686 ||
+ Distro == Fedora13X86_64 || Distro == Fedora13i686)
+ ExtraOpts.push_back("--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 +1449,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..04288a2 100644
--- a/lib/Driver/ToolChains.h
+++ b/lib/Driver/ToolChains.h
@@ -317,7 +317,12 @@ 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::vector<std::string> ExtraOpts;
};
diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp
index cdaea98..1b5f6b5 100644
--- a/lib/Driver/Tools.cpp
+++ b/lib/Driver/Tools.cpp
@@ -3141,6 +3141,145 @@ 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;
+
+ for (std::vector<std::string>::const_iterator i = ToolChain.ExtraOpts.begin(),
+ e = ToolChain.ExtraOpts.end();
+ i != e; ++i)
+ CmdArgs.push_back(i->c_str());
+
+ if (!Args.hasArg(options::OPT_static)) {
+ CmdArgs.push_back("--eh-frame-hdr");
+ }
+
+ CmdArgs.push_back("-m");
+ if (ToolChain.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("elf_i386");
+ else if (ToolChain.getArch() == llvm::Triple::arm)
+ CmdArgs.push_back("armelf_linux_eabi");
+ else
+ CmdArgs.push_back("elf_x86_64");
+
+ if (Args.hasArg(options::OPT_static)) {
+ if (ToolChain.getArch() == llvm::Triple::arm)
+ CmdArgs.push_back("-Bstatic");
+ else
+ CmdArgs.push_back("-static");
+ } else if (Args.hasArg(options::OPT_shared)) {
+ CmdArgs.push_back("-shared");
+ }
+
+ if (ToolChain.getArch() == llvm::Triple::arm ||
+ (!Args.hasArg(options::OPT_static) &&
+ !Args.hasArg(options::OPT_shared))) {
+ CmdArgs.push_back("-dynamic-linker");
+ if (ToolChain.getArch() == llvm::Triple::x86)
+ CmdArgs.push_back("/lib/ld-linux.so.2");
+ else if (ToolChain.getArch() == llvm::Triple::arm)
+ CmdArgs.push_back("/lib/ld-linux.so.3");
+ else
+ CmdArgs.push_back("/lib64/ld-linux-x86-64.so.2");
+ }
+
+ CmdArgs.push_back("-o");
+ CmdArgs.push_back(Output.getFilename());
+
+ 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");
+ }
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--start-group");
+
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+
+ if (Args.hasArg(options::OPT_static)) {
+ if (D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+ } else {
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--no-as-needed");
+ }
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("-lgcc_eh");
+ else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+
+ CmdArgs.push_back("-lc");
+
+ if (Args.hasArg(options::OPT_static))
+ CmdArgs.push_back("--end-group");
+ else {
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--as-needed");
+ CmdArgs.push_back("-lgcc_s");
+ if (!D.CCCIsCXX)
+ CmdArgs.push_back("--no-as-needed");
+
+ if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX)
+ CmdArgs.push_back("-lgcc");
+ }
+
+ 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