diff gen/linker.cpp @ 276:21f85bac0b1a trunk

[svn r297] Fixed: rewrote linker code to use LLVM's Program facilities instead of DMD's oldschool broken "native" approach.
author lindquist
date Fri, 20 Jun 2008 17:45:13 +0200
parents a95056b3c996
children 90a8c798b0db
line wrap: on
line diff
--- a/gen/linker.cpp	Thu Jun 19 17:30:32 2008 +0200
+++ b/gen/linker.cpp	Fri Jun 20 17:45:13 2008 +0200
@@ -1,8 +1,15 @@
 #include "gen/llvm.h"
 #include "llvm/Linker.h"
+#include "llvm/System/Program.h"
 
 #include "root.h"
 #include "mars.h"
+#include "module.h"
+
+#define NO_COUT_LOGGER
+#include "gen/logger.h"
+
+//////////////////////////////////////////////////////////////////////////////
 
 typedef std::vector<llvm::Module*> Module_vector;
 
@@ -23,3 +30,154 @@
         }
     }
 }
+
+//////////////////////////////////////////////////////////////////////////////
+
+int linkExecutable()
+{
+    Logger::println("*** Linking executable ***");
+
+    // error string
+    std::string errstr;
+
+    // find the llvm-ld program
+    llvm::sys::Path ldpath = llvm::sys::Program::FindProgramByName("llvm-ld");
+    if (ldpath.isEmpty())
+    {
+        error("linker program not found");
+        fatal();
+    }
+
+    // build arguments
+    std::vector<const char*> args;
+
+    // first the program name ??
+    args.push_back("llvm-ld");
+
+    // output filename
+    std::string exestr;
+    if (global.params.exefile)
+    {   // explicit
+        exestr = global.params.exefile;
+    }
+    else
+    {   // inferred
+        // try root module name
+        if (Module::rootModule)
+            exestr = Module::rootModule->toChars();
+        else
+            exestr = "a.out";
+    }
+    if (global.params.isWindows)
+        exestr.append(".exe");
+
+    std::string outopt = "-o=" + exestr;
+    args.push_back(outopt.c_str());
+
+    // create path to exe
+    llvm::sys::Path exepath(exestr);
+    exepath.set(exepath.getDirname());
+    exepath.createDirectoryOnDisk(true, &errstr);
+    if (!errstr.empty())
+    {
+        error("failed to create path to linking output\n%s", errstr.c_str());
+        fatal();
+    }
+
+    // strip debug info
+    if (!global.params.symdebug)
+        args.push_back("-strip-debug");
+
+    // optimization level
+    if (!global.params.optimize)
+        args.push_back("-disable-opt");
+    else
+    {
+        const char* s = 0;
+        switch(global.params.optimizeLevel)
+        {
+        case 0:
+            s = "-O0"; break;
+        case 1:
+            s = "-O1"; break;
+        case 2:
+            s = "-O2"; break;
+        case 3:
+            s = "-O3"; break;
+        case 4:
+            s = "-O4"; break;
+        case 5:
+            s = "-O5"; break;
+        default:
+            assert(0);
+        }
+        args.push_back(s);
+    }
+
+    // inlining
+    if (!(global.params.useInline || global.params.llvmInline))
+    {
+        args.push_back("-disable-inlining");
+    }
+
+    // additional linker switches
+    for (int i = 0; i < global.params.linkswitches->dim; i++)
+    {
+        char *p = (char *)global.params.linkswitches->data[i];
+        args.push_back(p);
+    }
+
+    // native please
+    args.push_back("-native");
+
+
+    // user libs
+    for (int i = 0; i < global.params.libfiles->dim; i++)
+    {
+        char *p = (char *)global.params.libfiles->data[i];
+        args.push_back(p);
+    }
+
+    // default libs
+    args.push_back("-ltango-base-c-llvmdc");
+    args.push_back("-lpthread");
+    args.push_back("-ldl");
+    args.push_back("-lm");
+
+    // object files
+    for (int i = 0; i < global.params.objfiles->dim; i++)
+    {
+        char *p = (char *)global.params.objfiles->data[i];
+        args.push_back(p);
+    }
+
+    // runtime library
+    // must be linked in last to null terminate the moduleinfo appending list
+    std::string runtime_path(global.params.runtimePath);
+    if (*runtime_path.rbegin() != '/')
+        runtime_path.append("/");
+    runtime_path.append("libtango-base-llvmdc.a");
+    args.push_back(runtime_path.c_str());
+
+    // print link command?
+    if (!global.params.quiet || global.params.verbose)
+    {
+        // Print it
+        for (int i = 0; i < args.size(); i++)
+            printf("%s ", args[i]);
+        printf("\n");
+        fflush(stdout);
+    }
+
+    // terminate args list
+    args.push_back(NULL);
+
+    // try to call linker!!!
+    if (int status = llvm::sys::Program::ExecuteAndWait(ldpath, &args[0], NULL, NULL, 0,0, &errstr))
+    {
+        error("linking failed:\nstatus: %d", status);
+        if (!errstr.empty())
+            error("message: %s", errstr.c_str());
+        fatal();
+    }
+}